Index: libcomm/comm_user.c
===================================================================
RCS file: /cvs/xorp/libcomm/comm_user.c,v
retrieving revision 1.23
diff -u -r1.23 comm_user.c
--- libcomm/comm_user.c	12 Oct 2006 01:24:45 -0000	1.23
+++ libcomm/comm_user.c	26 Mar 2007 12:14:01 -0000
@@ -258,6 +258,24 @@
 }
 
 /**
+ * comm_listen:
+ * @sock the socket to listen on.
+ * @backlog the maximum queue size for pending connections.
+ *
+ * Listen on a socket.
+ *
+ * Return value: %XORP_OK on success, otherwise %XORP_ERROR.
+ **/
+int
+comm_listen(xsock_t sock, int backlog)
+{
+    if (comm_sock_listen(sock, backlog) != XORP_OK)
+	return (XORP_ERROR);
+
+    return (XORP_OK);
+}
+
+/**
  * comm_bind_tcp4:
  * @my_addr: The local IPv4 address to bind to (in network order).
  * If it is NULL, will bind to `any' local address.
@@ -288,14 +306,6 @@
 	return (XORP_BAD_SOCKET);
     }
 
-    if (listen(sock, 5) < 0) {
-	_comm_set_serrno();
-	XLOG_ERROR("Error listen() on socket %d: %s",
-		   sock, comm_get_error_str(comm_get_last_error()));
-	comm_sock_close(sock);
-	return (XORP_BAD_SOCKET);
-    }
-
     return (sock);
 }
 
@@ -331,14 +341,6 @@
 	return (XORP_BAD_SOCKET);
     }
 
-    if (listen(sock, 5) < 0) {
-	_comm_set_serrno();
-	XLOG_ERROR("Error listen() on socket %d: %s",
-		   sock, comm_get_error_str(comm_get_last_error()));
-	comm_sock_close(sock);
-	return (XORP_BAD_SOCKET);
-    }
-
     return (sock);
 
 #else /* ! HAVE_IPV6 */
@@ -363,16 +365,17 @@
     switch (sock->sa_family) {
     case AF_INET:
 	{
-	    const struct sockaddr_in *sin = (const struct sockaddr_in *)((const void *)sock);
+	    const struct sockaddr_in *sin =
+		(const struct sockaddr_in *)((const void *)sock);
 	    return comm_bind_tcp4(&sin->sin_addr, sin->sin_port, is_blocking);
 	}
 	break;
 #ifdef HAVE_IPV6
     case AF_INET6:
 	{
-	    const struct sockaddr_in6 *sin = (const struct sockaddr_in6 *)((const void *)sock);
-	    return comm_bind_tcp6(&sin->sin6_addr, sin->sin6_port,
-				  is_blocking);
+	    const struct sockaddr_in6 *sin =
+		(const struct sockaddr_in6 *)((const void *)sock);
+	    return comm_bind_tcp6(&sin->sin6_addr, sin->sin6_port, is_blocking);
 	}
 	break;
 #endif /* HAVE_IPV6 */
Index: libcomm/test_comm.c
===================================================================
RCS file: /cvs/xorp/libcomm/test_comm.c,v
retrieving revision 1.13
diff -u -r1.13 test_comm.c
--- libcomm/test_comm.c	16 Feb 2007 22:45:59 -0000	1.13
+++ libcomm/test_comm.c	26 Mar 2007 12:14:01 -0000
@@ -151,6 +151,23 @@
     } else {
 	printf("OK: open, bind and join UDP socket to group %s and port %d\n",
 	       inet_ntoa(mcast_addr), ntohs(port));
+	comm_close(sock);
+    }
+
+    /*
+     * Test 'listen on socket'
+     */
+    sock = comm_bind_tcp4(NULL, port, COMM_SOCK_BLOCKING);
+    if (sock == XORP_BAD_SOCKET) {
+	printf("ERROR: cannot open and bind TCP socket to port %d,"
+	       " for listening\n", ntohs(port));
+    } else if (comm_listen(sock, 5) != XORP_OK) {
+	printf("ERROR: listening TCP socket on port %d\n", ntohs(port));
+	comm_close(sock);
+    } else {
+        printf("OK: open, bind and listen TCP socket on port %d\n",
+	       ntohs(port));
+	comm_close(sock);
     }
 
 
Index: libcomm/comm_api.h
===================================================================
RCS file: /cvs/xorp/libcomm/comm_api.h,v
retrieving revision 1.22
diff -u -r1.22 comm_api.h
--- libcomm/comm_api.h	1 Mar 2006 12:55:33 -0000	1.22
+++ libcomm/comm_api.h	26 Mar 2007 12:14:01 -0000
@@ -62,6 +62,8 @@
 #define COMM_SOCK_BLOCKING		1
 #define COMM_SOCK_NONBLOCKING		0
 
+#define COMM_DEFAULT_BACKLOG		5
+
 #ifndef AF_LOCAL
 #define AF_LOCAL		AF_UNIX	   /* XXX: AF_UNIX is the older name */
 #endif
@@ -173,6 +175,15 @@
 extern int	comm_close(xsock_t sock);
 
 /**
+ * Listen on a socket.
+ *
+ * @param sock the socket to listen on.
+ * @param backlog the maximum queue size for pending connections.
+ * @return XORP_OK on success, otherwise XORP_ERROR.
+ */
+extern int	comm_listen(xsock_t sock, int backlog);
+
+/**
  * Open an IPv4 TCP socket and bind it to a local address and a port.
  *
  * @param my_addr the local IPv4 address to bind to (in network order).
@@ -635,6 +646,15 @@
 extern xsock_t	comm_sock_accept(xsock_t sock);
 
 /**
+ * Listen for connections on a socket.
+ *
+ * @param sock the socket to listen on.
+ * @param backlog the maximum queue size for pending connections
+ * @return XORP_OK on success, otherwise XORP_ERROR.
+ */
+extern int	comm_sock_listen(xsock_t sock, int backlog);
+
+/**
  * Close a socket.
  *
  * @param sock the socket to close.
@@ -758,6 +778,15 @@
 extern int	comm_sock_get_family(xsock_t sock);
 
 /**
+ * Get the type of a socket.
+ * Code copied from comm_sock_get_family.
+ *
+ * @param sock the socket whose type we need to get.
+ * @return the socket type on success, otherwise XORP_ERROR.
+ */
+extern int	comm_sock_get_type(xsock_t sock);
+
+/**
  * Set the blocking or non-blocking mode of an existing socket.
  * @param sock the socket whose blocking mode is to be set.
  * @param is_blocking if non-zero, then set socket to blocking mode.
Index: libcomm/comm_sock.c
===================================================================
RCS file: /cvs/xorp/libcomm/comm_sock.c,v
retrieving revision 1.34
diff -u -r1.34 comm_sock.c
--- libcomm/comm_sock.c	12 Oct 2006 01:24:45 -0000	1.34
+++ libcomm/comm_sock.c	26 Mar 2007 12:14:01 -0000
@@ -919,6 +919,31 @@
 }
 
 /**
+ * comm_sock_listen:
+ * @sock: The socket to listen on.
+ * @backlog: The maximum queue size for pending connections.
+ *
+ * Listen on a socket.
+ *
+ * Return value: %XORP_OK on success, otherwise %XORP_ERROR.
+ **/
+int
+comm_sock_listen(xsock_t sock, int backlog)
+{
+    int ret;
+    ret = listen(sock, backlog);
+
+    if (ret < 0) {
+	_comm_set_serrno();
+	XLOG_ERROR("Error listening on socket (socket = %d) : %s",
+		   sock, comm_get_error_str(comm_get_last_error()));
+	return (XORP_ERROR);
+    }
+
+    return (XORP_OK);
+}
+
+/**
  * comm_sock_close:
  * @sock: The socket to close.
  *
@@ -1419,6 +1444,33 @@
 }
 
 /**
+ * comm_sock_get_type:
+ * @sock: The socket whose type we need to get.
+ *
+ * Get the type of a socket.
+ * Code taken from comm_sock_get_family
+ *
+ * Return value: The socket type on success, otherwise %XORP_ERROR.
+ **/
+int
+comm_sock_get_type(xsock_t sock)
+{
+    int err, type;
+    socklen_t len = sizeof(type);
+
+    err = getsockopt(sock, SOL_SOCKET, SO_TYPE,
+		     XORP_SOCKOPT_CAST(&type), &len);
+    if (err != 0)  {
+	_comm_set_serrno();
+	XLOG_ERROR("Error getsockopt(SO_TYPE) for socket %d: %s",
+		   sock, comm_get_error_str(comm_get_last_error()));
+	return (XORP_ERROR);
+    }
+
+    return type;
+}
+
+/**
  * comm_sock_set_blocking:
  *
  * Set the blocking or non-blocking mode of an existing socket.
Index: xrl/targets/socket_server_base.hh
===================================================================
RCS file: /cvs/xorp/xrl/targets/socket_server_base.hh,v
retrieving revision 1.11
diff -u -r1.11 socket_server_base.hh
--- xrl/targets/socket_server_base.hh	16 Feb 2007 22:47:57 -0000	1.11
+++ xrl/targets/socket_server_base.hh	26 Mar 2007 12:14:03 -0000
@@ -130,6 +130,66 @@
     /**
      *  Pure-virtual function that needs to be implemented to:
      *
+     *  Open a tcp socket.
+     *
+     *  @param creator the Xrl Target instance name of the socket creator. The
+     *  named target must implement socket4_user/0.1.
+     *
+     *  @param is_blocking if true then the socket will be blocking, otherwise
+     *  non-blocking.
+     *
+     *  @param sockid return parameter that contains unique socket id when
+     *  socket instantiation is successful.
+     */
+    virtual XrlCmdError socket4_0_1_tcp_open(
+	// Input values,
+	const string&	creator,
+	const bool&	is_blocking,
+	// Output values,
+	string&	sockid) = 0;
+
+    /**
+     *  Pure-virtual function that needs to be implemented to:
+     *
+     *  Open a udp socket.
+     *
+     *  @param creator the Xrl Target instance name of the socket creator. The
+     *  named target must implement socket4_user/0.1.
+     *
+     *  @param is_blocking if true then the socket will be blocking, otherwise
+     *  non-blocking.
+     *
+     *  @param sockid return parameter that contains unique socket id when
+     *  socket instantiation is successful.
+     */
+    virtual XrlCmdError socket4_0_1_udp_open(
+	// Input values,
+	const string&	creator,
+	const bool&	is_blocking,
+	// Output values,
+	string&	sockid) = 0;
+
+    /**
+     *  Pure-virtual function that needs to be implemented to:
+     *
+     *  Bind a socket.
+     *
+     *  @param sockid the socket id of the socket to bind.
+     *
+     *  @param local_addr the interface address to bind socket to.
+     *
+     *  @param local_port the port to bind socket to.
+     */
+    virtual XrlCmdError socket4_0_1_bind(
+	// Input values,
+	const string&	creator,
+	const string&	sockid,
+	const IPv4&	local_addr,
+	const uint32_t&	local_port) = 0;
+
+    /**
+     *  Pure-virtual function that needs to be implemented to:
+     *
      *  Create a bound TCP socket.
      *
      *  @param creator the Xrl Target instance name of the socket creator. The
@@ -501,6 +561,66 @@
     /**
      *  Pure-virtual function that needs to be implemented to:
      *
+     *  Open a tcp socket.
+     *
+     *  @param creator the Xrl Target instance name of the socket creator. The
+     *  named target must implement socket4_user/0.1.
+     *
+     *  @param is_blocking if true then the socket will be blocking, otherwise
+     *  non-blocking.
+     *
+     *  @param sockid return parameter that contains unique socket id when
+     *  socket instantiation is successful.
+     */
+    virtual XrlCmdError socket6_0_1_tcp_open(
+	// Input values,
+	const string&	creator,
+	const bool&	is_blocking,
+	// Output values,
+	string&	sockid) = 0;
+
+    /**
+     *  Pure-virtual function that needs to be implemented to:
+     *
+     *  Open a udp socket.
+     *
+     *  @param creator the Xrl Target instance name of the socket creator. The
+     *  named target must implement socket4_user/0.1.
+     *
+     *  @param is_blocking if true then the socket will be blocking, otherwise
+     *  non-blocking.
+     *
+     *  @param sockid return parameter that contains unique socket id when
+     *  socket instantiation is successful.
+     */
+    virtual XrlCmdError socket6_0_1_udp_open(
+	// Input values,
+	const string&	creator,
+	const bool&	is_blocking,
+	// Output values,
+	string&	sockid) = 0;
+
+    /**
+     *  Pure-virtual function that needs to be implemented to:
+     *
+     *  Bind a socket.
+     *
+     *  @param sockid the socket id of the socket to bind.
+     *
+     *  @param local_addr the interface address to bind socket to.
+     *
+     *  @param local_port the port to bind socket to.
+     */
+    virtual XrlCmdError socket6_0_1_bind(
+	// Input values,
+	const string&	creator,
+	const string&	sockid,
+	const IPv6&	local_addr,
+	const uint32_t&	local_port) = 0;
+
+    /**
+     *  Pure-virtual function that needs to be implemented to:
+     *
      *  Create a bound TCP socket.
      *
      *  @param creator the Xrl Target instance name of the socket creator. The
@@ -882,6 +1002,12 @@
 
     const XrlCmdError handle_finder_event_observer_0_1_xrl_target_death(const XrlArgs& in, XrlArgs* out);
 
+    const XrlCmdError handle_socket4_0_1_tcp_open(const XrlArgs& in, XrlArgs* out);
+
+    const XrlCmdError handle_socket4_0_1_udp_open(const XrlArgs& in, XrlArgs* out);
+
+    const XrlCmdError handle_socket4_0_1_bind(const XrlArgs& in, XrlArgs* out);
+
     const XrlCmdError handle_socket4_0_1_tcp_open_and_bind(const XrlArgs& in, XrlArgs* out);
 
     const XrlCmdError handle_socket4_0_1_udp_open_and_bind(const XrlArgs& in, XrlArgs* out);
@@ -914,6 +1040,12 @@
 
     const XrlCmdError handle_socket4_0_1_get_socket_option(const XrlArgs& in, XrlArgs* out);
 
+    const XrlCmdError handle_socket6_0_1_tcp_open(const XrlArgs& in, XrlArgs* out);
+
+    const XrlCmdError handle_socket6_0_1_udp_open(const XrlArgs& in, XrlArgs* out);
+
+    const XrlCmdError handle_socket6_0_1_bind(const XrlArgs& in, XrlArgs* out);
+
     const XrlCmdError handle_socket6_0_1_tcp_open_and_bind(const XrlArgs& in, XrlArgs* out);
 
     const XrlCmdError handle_socket6_0_1_udp_open_and_bind(const XrlArgs& in, XrlArgs* out);
Index: xrl/targets/socket_server.xrls
===================================================================
RCS file: /cvs/xorp/xrl/targets/socket_server.xrls,v
retrieving revision 1.9
diff -u -r1.9 socket_server.xrls
--- xrl/targets/socket_server.xrls	16 Feb 2007 22:47:57 -0000	1.9
+++ xrl/targets/socket_server.xrls	26 Mar 2007 12:14:02 -0000
@@ -48,6 +48,45 @@
 finder://socket_server/finder_event_observer/0.1/xrl_target_death?target_class:txt&target_instance:txt
 
 /**
+ *  Open a tcp socket.
+ *
+ *  @param creator the Xrl Target instance name of the socket creator. The
+ *  named target must implement socket4_user/0.1.
+ *
+ *  @param is_blocking if true then the socket will be blocking, otherwise
+ *  non-blocking.
+ *
+ *  @param sockid return parameter that contains unique socket id when socket
+ *  instantiation is successful.
+ */
+finder://socket_server/socket4/0.1/tcp_open?creator:txt&is_blocking:bool->sockid:txt
+
+/**
+ *  Open a udp socket.
+ *
+ *  @param creator the Xrl Target instance name of the socket creator. The
+ *  named target must implement socket4_user/0.1.
+ *
+ *  @param is_blocking if true then the socket will be blocking, otherwise
+ *  non-blocking.
+ *
+ *  @param sockid return parameter that contains unique socket id when socket
+ *  instantiation is successful.
+ */
+finder://socket_server/socket4/0.1/udp_open?creator:txt&is_blocking:bool->sockid:txt
+
+/**
+ *  Bind a socket.
+ *
+ *  @param sockid the socket id of the socket to bind.
+ *
+ *  @param local_addr the interface address to bind socket to.
+ *
+ *  @param local_port the port to bind socket to.
+ */
+finder://socket_server/socket4/0.1/bind?creator:txt&sockid:txt&local_addr:ipv4&local_port:u32
+
+/**
  *  Create a bound TCP socket.
  *
  *  @param creator the Xrl Target instance name of the socket creator. The
@@ -295,6 +334,45 @@
 finder://socket_server/socket4/0.1/get_socket_option?sockid:txt&optname:txt->optval:u32
 
 /**
+ *  Open a tcp socket.
+ *
+ *  @param creator the Xrl Target instance name of the socket creator. The
+ *  named target must implement socket4_user/0.1.
+ *
+ *  @param is_blocking if true then the socket will be blocking, otherwise
+ *  non-blocking.
+ *
+ *  @param sockid return parameter that contains unique socket id when socket
+ *  instantiation is successful.
+ */
+finder://socket_server/socket6/0.1/tcp_open?creator:txt&is_blocking:bool->sockid:txt
+
+/**
+ *  Open a udp socket.
+ *
+ *  @param creator the Xrl Target instance name of the socket creator. The
+ *  named target must implement socket4_user/0.1.
+ *
+ *  @param is_blocking if true then the socket will be blocking, otherwise
+ *  non-blocking.
+ *
+ *  @param sockid return parameter that contains unique socket id when socket
+ *  instantiation is successful.
+ */
+finder://socket_server/socket6/0.1/udp_open?creator:txt&is_blocking:bool->sockid:txt
+
+/**
+ *  Bind a socket.
+ *
+ *  @param sockid the socket id of the socket to bind.
+ *
+ *  @param local_addr the interface address to bind socket to.
+ *
+ *  @param local_port the port to bind socket to.
+ */
+finder://socket_server/socket6/0.1/bind?creator:txt&sockid:txt&local_addr:ipv6&local_port:u32
+
+/**
  *  Create a bound TCP socket.
  *
  *  @param creator the Xrl Target instance name of the socket creator. The
Index: xrl/targets/socket_server_base.cc
===================================================================
RCS file: /cvs/xorp/xrl/targets/socket_server_base.cc,v
retrieving revision 1.11
diff -u -r1.11 socket_server_base.cc
--- xrl/targets/socket_server_base.cc	16 Feb 2007 22:47:57 -0000	1.11
+++ xrl/targets/socket_server_base.cc	26 Mar 2007 12:14:03 -0000
@@ -236,6 +236,114 @@
 }
 
 const XrlCmdError
+XrlSocketServerTargetBase::handle_socket4_0_1_tcp_open(const XrlArgs& xa_inputs, XrlArgs* pxa_outputs)
+{
+    if (xa_inputs.size() != 2) {
+	XLOG_ERROR("Wrong number of arguments (%u != %u) handling %s",
+            XORP_UINT_CAST(2), XORP_UINT_CAST(xa_inputs.size()), "socket4/0.1/tcp_open");
+	return XrlCmdError::BAD_ARGS();
+    }
+
+    if (pxa_outputs == 0) {
+	XLOG_FATAL("Return list empty");
+	return XrlCmdError::BAD_ARGS();
+    }
+
+    /* Return value declarations */
+    string sockid;
+    try {
+	XrlCmdError e = socket4_0_1_tcp_open(
+	    xa_inputs.get_string("creator"),
+	    xa_inputs.get_bool("is_blocking"),
+	    sockid);
+	if (e != XrlCmdError::OKAY()) {
+	    XLOG_WARNING("Handling method for %s failed: %s",
+            		 "socket4/0.1/tcp_open", e.str().c_str());
+	    return e;
+        }
+    } catch (const XrlArgs::XrlAtomNotFound& e) {
+	XLOG_ERROR("Argument not found");
+	return XrlCmdError::BAD_ARGS();
+    }
+
+    /* Marshall return values */
+    try {
+	pxa_outputs->add("sockid", sockid);
+    } catch (const XrlArgs::XrlAtomFound& ) {
+	XLOG_FATAL("Duplicate atom name"); /* XXX Should never happen */
+    }
+    return XrlCmdError::OKAY();
+}
+
+const XrlCmdError
+XrlSocketServerTargetBase::handle_socket4_0_1_udp_open(const XrlArgs& xa_inputs, XrlArgs* pxa_outputs)
+{
+    if (xa_inputs.size() != 2) {
+	XLOG_ERROR("Wrong number of arguments (%u != %u) handling %s",
+            XORP_UINT_CAST(2), XORP_UINT_CAST(xa_inputs.size()), "socket4/0.1/udp_open");
+	return XrlCmdError::BAD_ARGS();
+    }
+
+    if (pxa_outputs == 0) {
+	XLOG_FATAL("Return list empty");
+	return XrlCmdError::BAD_ARGS();
+    }
+
+    /* Return value declarations */
+    string sockid;
+    try {
+	XrlCmdError e = socket4_0_1_udp_open(
+	    xa_inputs.get_string("creator"),
+	    xa_inputs.get_bool("is_blocking"),
+	    sockid);
+	if (e != XrlCmdError::OKAY()) {
+	    XLOG_WARNING("Handling method for %s failed: %s",
+            		 "socket4/0.1/udp_open", e.str().c_str());
+	    return e;
+        }
+    } catch (const XrlArgs::XrlAtomNotFound& e) {
+	XLOG_ERROR("Argument not found");
+	return XrlCmdError::BAD_ARGS();
+    }
+
+    /* Marshall return values */
+    try {
+	pxa_outputs->add("sockid", sockid);
+    } catch (const XrlArgs::XrlAtomFound& ) {
+	XLOG_FATAL("Duplicate atom name"); /* XXX Should never happen */
+    }
+    return XrlCmdError::OKAY();
+}
+
+const XrlCmdError
+XrlSocketServerTargetBase::handle_socket4_0_1_bind(const XrlArgs& xa_inputs, XrlArgs* /* pxa_outputs */)
+{
+    if (xa_inputs.size() != 4) {
+	XLOG_ERROR("Wrong number of arguments (%u != %u) handling %s",
+            XORP_UINT_CAST(4), XORP_UINT_CAST(xa_inputs.size()), "socket4/0.1/bind");
+	return XrlCmdError::BAD_ARGS();
+    }
+
+    /* Return value declarations */
+    try {
+	XrlCmdError e = socket4_0_1_bind(
+	    xa_inputs.get_string("creator"),
+	    xa_inputs.get_string("sockid"),
+	    xa_inputs.get_ipv4("local_addr"),
+	    xa_inputs.get_uint32("local_port"));
+	if (e != XrlCmdError::OKAY()) {
+	    XLOG_WARNING("Handling method for %s failed: %s",
+            		 "socket4/0.1/bind", e.str().c_str());
+	    return e;
+        }
+    } catch (const XrlArgs::XrlAtomNotFound& e) {
+	XLOG_ERROR("Argument not found");
+	return XrlCmdError::BAD_ARGS();
+    }
+    return XrlCmdError::OKAY();
+}
+
+const XrlCmdError
 XrlSocketServerTargetBase::handle_socket4_0_1_tcp_open_and_bind(const XrlArgs& xa_inputs, XrlArgs* pxa_outputs)
 {
     if (xa_inputs.size() != 4) {
@@ -768,6 +876,114 @@
 }
 
 const XrlCmdError
+XrlSocketServerTargetBase::handle_socket6_0_1_tcp_open(const XrlArgs& xa_inputs, XrlArgs* pxa_outputs)
+{
+    if (xa_inputs.size() != 2) {
+	XLOG_ERROR("Wrong number of arguments (%u != %u) handling %s",
+            XORP_UINT_CAST(2), XORP_UINT_CAST(xa_inputs.size()), "socket6/0.1/tcp_open");
+	return XrlCmdError::BAD_ARGS();
+    }
+
+    if (pxa_outputs == 0) {
+	XLOG_FATAL("Return list empty");
+	return XrlCmdError::BAD_ARGS();
+    }
+
+    /* Return value declarations */
+    string sockid;
+    try {
+	XrlCmdError e = socket6_0_1_tcp_open(
+	    xa_inputs.get_string("creator"),
+	    xa_inputs.get_bool("is_blocking"),
+	    sockid);
+	if (e != XrlCmdError::OKAY()) {
+	    XLOG_WARNING("Handling method for %s failed: %s",
+            		 "socket6/0.1/tcp_open", e.str().c_str());
+	    return e;
+        }
+    } catch (const XrlArgs::XrlAtomNotFound& e) {
+	XLOG_ERROR("Argument not found");
+	return XrlCmdError::BAD_ARGS();
+    }
+
+    /* Marshall return values */
+    try {
+	pxa_outputs->add("sockid", sockid);
+    } catch (const XrlArgs::XrlAtomFound& ) {
+	XLOG_FATAL("Duplicate atom name"); /* XXX Should never happen */
+    }
+    return XrlCmdError::OKAY();
+}
+
+const XrlCmdError
+XrlSocketServerTargetBase::handle_socket6_0_1_udp_open(const XrlArgs& xa_inputs, XrlArgs* pxa_outputs)
+{
+    if (xa_inputs.size() != 2) {
+	XLOG_ERROR("Wrong number of arguments (%u != %u) handling %s",
+            XORP_UINT_CAST(2), XORP_UINT_CAST(xa_inputs.size()), "socket6/0.1/udp_open");
+	return XrlCmdError::BAD_ARGS();
+    }
+
+    if (pxa_outputs == 0) {
+	XLOG_FATAL("Return list empty");
+	return XrlCmdError::BAD_ARGS();
+    }
+
+    /* Return value declarations */
+    string sockid;
+    try {
+	XrlCmdError e = socket6_0_1_udp_open(
+	    xa_inputs.get_string("creator"),
+	    xa_inputs.get_bool("is_blocking"),
+	    sockid);
+	if (e != XrlCmdError::OKAY()) {
+	    XLOG_WARNING("Handling method for %s failed: %s",
+            		 "socket6/0.1/udp_open", e.str().c_str());
+	    return e;
+        }
+    } catch (const XrlArgs::XrlAtomNotFound& e) {
+	XLOG_ERROR("Argument not found");
+	return XrlCmdError::BAD_ARGS();
+    }
+
+    /* Marshall return values */
+    try {
+	pxa_outputs->add("sockid", sockid);
+    } catch (const XrlArgs::XrlAtomFound& ) {
+	XLOG_FATAL("Duplicate atom name"); /* XXX Should never happen */
+    }
+    return XrlCmdError::OKAY();
+}
+
+const XrlCmdError
+XrlSocketServerTargetBase::handle_socket6_0_1_bind(const XrlArgs& xa_inputs, XrlArgs* /* pxa_outputs */)
+{
+    if (xa_inputs.size() != 4) {
+	XLOG_ERROR("Wrong number of arguments (%u != %u) handling %s",
+            XORP_UINT_CAST(4), XORP_UINT_CAST(xa_inputs.size()), "socket6/0.1/bind");
+	return XrlCmdError::BAD_ARGS();
+    }
+
+    /* Return value declarations */
+    try {
+	XrlCmdError e = socket6_0_1_bind(
+	    xa_inputs.get_string("creator"),
+	    xa_inputs.get_string("sockid"),
+	    xa_inputs.get_ipv6("local_addr"),
+	    xa_inputs.get_uint32("local_port"));
+	if (e != XrlCmdError::OKAY()) {
+	    XLOG_WARNING("Handling method for %s failed: %s",
+            		 "socket6/0.1/bind", e.str().c_str());
+	    return e;
+        }
+    } catch (const XrlArgs::XrlAtomNotFound& e) {
+	XLOG_ERROR("Argument not found");
+	return XrlCmdError::BAD_ARGS();
+    }
+    return XrlCmdError::OKAY();
+}
+
+const XrlCmdError
 XrlSocketServerTargetBase::handle_socket6_0_1_tcp_open_and_bind(const XrlArgs& xa_inputs, XrlArgs* pxa_outputs)
 {
     if (xa_inputs.size() != 4) {
@@ -1326,6 +1542,18 @@
 	    callback(this, &XrlSocketServerTargetBase::handle_finder_event_observer_0_1_xrl_target_death)) == false) {
 	    XLOG_ERROR("Failed to xrl handler finder://%s/%s", "socket_server", "finder_event_observer/0.1/xrl_target_death");
 	}
+	if (_cmds->add_handler("socket4/0.1/tcp_open",
+	    callback(this, &XrlSocketServerTargetBase::handle_socket4_0_1_tcp_open)) == false) {
+	    XLOG_ERROR("Failed to xrl handler finder://%s/%s", "socket_server", "socket4/0.1/tcp_open");
+	}
+	if (_cmds->add_handler("socket4/0.1/udp_open",
+	    callback(this, &XrlSocketServerTargetBase::handle_socket4_0_1_udp_open)) == false) {
+	    XLOG_ERROR("Failed to xrl handler finder://%s/%s", "socket_server", "socket4/0.1/udp_open");
+	}
+	if (_cmds->add_handler("socket4/0.1/bind",
+	    callback(this, &XrlSocketServerTargetBase::handle_socket4_0_1_bind)) == false) {
+	    XLOG_ERROR("Failed to xrl handler finder://%s/%s", "socket_server", "socket4/0.1/bind");
+	}
 	if (_cmds->add_handler("socket4/0.1/tcp_open_and_bind",
 	    callback(this, &XrlSocketServerTargetBase::handle_socket4_0_1_tcp_open_and_bind)) == false) {
 	    XLOG_ERROR("Failed to xrl handler finder://%s/%s", "socket_server", "socket4/0.1/tcp_open_and_bind");
@@ -1390,6 +1618,18 @@
 	    callback(this, &XrlSocketServerTargetBase::handle_socket4_0_1_get_socket_option)) == false) {
 	    XLOG_ERROR("Failed to xrl handler finder://%s/%s", "socket_server", "socket4/0.1/get_socket_option");
 	}
+	if (_cmds->add_handler("socket6/0.1/tcp_open",
+	    callback(this, &XrlSocketServerTargetBase::handle_socket6_0_1_tcp_open)) == false) {
+	    XLOG_ERROR("Failed to xrl handler finder://%s/%s", "socket_server", "socket6/0.1/tcp_open");
+	}
+	if (_cmds->add_handler("socket6/0.1/udp_open",
+	    callback(this, &XrlSocketServerTargetBase::handle_socket6_0_1_udp_open)) == false) {
+	    XLOG_ERROR("Failed to xrl handler finder://%s/%s", "socket_server", "socket6/0.1/udp_open");
+	}
+	if (_cmds->add_handler("socket6/0.1/bind",
+	    callback(this, &XrlSocketServerTargetBase::handle_socket6_0_1_bind)) == false) {
+	    XLOG_ERROR("Failed to xrl handler finder://%s/%s", "socket_server", "socket6/0.1/bind");
+	}
 	if (_cmds->add_handler("socket6/0.1/tcp_open_and_bind",
 	    callback(this, &XrlSocketServerTargetBase::handle_socket6_0_1_tcp_open_and_bind)) == false) {
 	    XLOG_ERROR("Failed to xrl handler finder://%s/%s", "socket_server", "socket6/0.1/tcp_open_and_bind");
@@ -1466,6 +1706,9 @@
 	_cmds->remove_handler("common/0.1/shutdown");
 	_cmds->remove_handler("finder_event_observer/0.1/xrl_target_birth");
 	_cmds->remove_handler("finder_event_observer/0.1/xrl_target_death");
+	_cmds->remove_handler("socket4/0.1/tcp_open");
+	_cmds->remove_handler("socket4/0.1/udp_open");
+	_cmds->remove_handler("socket4/0.1/bind");
 	_cmds->remove_handler("socket4/0.1/tcp_open_and_bind");
 	_cmds->remove_handler("socket4/0.1/udp_open_and_bind");
 	_cmds->remove_handler("socket4/0.1/udp_open_bind_join");
@@ -1482,6 +1725,9 @@
 	_cmds->remove_handler("socket4/0.1/send_from_multicast_if");
 	_cmds->remove_handler("socket4/0.1/set_socket_option");
 	_cmds->remove_handler("socket4/0.1/get_socket_option");
+	_cmds->remove_handler("socket6/0.1/tcp_open");
+	_cmds->remove_handler("socket6/0.1/udp_open");
+	_cmds->remove_handler("socket6/0.1/bind");
 	_cmds->remove_handler("socket6/0.1/tcp_open_and_bind");
 	_cmds->remove_handler("socket6/0.1/udp_open_and_bind");
 	_cmds->remove_handler("socket6/0.1/udp_open_bind_join");
Index: bgp/harness/test_peer.cc
===================================================================
RCS file: /cvs/xorp/bgp/harness/test_peer.cc,v
retrieving revision 1.45
diff -u -r1.45 test_peer.cc
--- bgp/harness/test_peer.cc	16 Feb 2007 22:45:26 -0000	1.45
+++ bgp/harness/test_peer.cc	26 Mar 2007 12:13:57 -0000
@@ -409,6 +409,12 @@
 	return false;
     }
 
+    if (comm_listen(s, COMM_DEFAULT_BACKLOG) != XORP_OK) {
+	error_string = c_format("comm_listen() failed: %s\n",
+				comm_get_last_error_str());
+	return false;
+    }
+
     if(!_eventloop.add_ioevent_cb(s, IOT_ACCEPT,
 				callback(this,
 					 &TestPeer::connect_attempt))) {
Index: fea/xrl_socket_cmds.cc
===================================================================
RCS file: /cvs/xorp/fea/xrl_socket_cmds.cc,v
retrieving revision 1.8
diff -u -r1.8 xrl_socket_cmds.cc
--- fea/xrl_socket_cmds.cc	16 Feb 2007 22:45:53 -0000	1.8
+++ fea/xrl_socket_cmds.cc	26 Mar 2007 12:13:58 -0000
@@ -77,11 +77,58 @@
 template class SocketUserSendRecvEvent<IPv6>;
 
 // ----------------------------------------------------------------------------
-// Socket4UserSendConnectEvent
+// SocketUserSendConnectEvent
+
+template <>
+bool
+SocketUserSendConnectEvent<IPv4>::execute(XrlSender&		    xs,
+					  const CommandCallback&    cb)
+{
+    XrlSocket4UserV0p1Client c(&xs);
+    _cb = cb;
+	bool result = c.send_connect_event(target(), _sockid,
+	    _src_host, _src_port, _new_sockid,
+	    callback(this, &SocketUserSendConnectEvent::accept_or_reject_cb));
+    return result;
+}
+
+template <>
+bool
+SocketUserSendConnectEvent<IPv6>::execute(XrlSender&		    xs,
+					  const CommandCallback&    cb)
+{
+    XrlSocket6UserV0p1Client c(&xs);
+    _cb = cb;
+    bool result = c.send_connect_event(target(), _sockid,
+	_src_host, _src_port, _new_sockid,
+	callback(this, &SocketUserSendConnectEvent::accept_or_reject_cb));
+    return result;
+}
+
+template <typename A>
+void
+SocketUserSendConnectEvent<A>::accept_or_reject_cb(const XrlError&  e,
+						   const bool*	    accept)
+{
+    if (*accept)
+	_ss->accept_connection(_new_sockid);
+    else
+	_ss->reject_connection(_new_sockid);
+    _cb->dispatch(e);
+}
+
+template <typename A>
+string
+SocketUserSendConnectEvent<A>::str() const
+{
+    return c_format("SendConnectEvent(%s, %s, %u, %s)",
+		    _sockid.c_str(), _src_host.str().c_str(),
+		    XORP_UINT_CAST(_src_port), _new_sockid.c_str());
+}
+
+template class SocketUserSendConnectEvent<IPv4>;
+template class SocketUserSendConnectEvent<IPv6>;
 
-//
-// ... Socket4UserSendConnectEvent ...
-//
 
 // ----------------------------------------------------------------------------
 // Socket4UserSendErrorEvent
@@ -166,7 +213,7 @@
     const Command& cmd = _cmds.front();
 
     bool r = cmd->execute(_xs,
-			  callback(this, &XrlSocketCommandDispatcher::xrl_cb));
+		callback(this, &XrlSocketCommandDispatcher::xrl_cb));
     if (r == false) {
 	XLOG_ERROR("Command failed discarding: %s", cmd->str().c_str());
 	_cmds.pop_front();
Index: fea/Jamfile
===================================================================
RCS file: /cvs/xorp/fea/Jamfile,v
retrieving revision 1.1
diff -u -r1.1 Jamfile
--- fea/Jamfile	11 Jan 2007 22:30:46 -0000	1.1
+++ fea/Jamfile	26 Mar 2007 12:13:58 -0000
@@ -244,6 +244,21 @@
 	libxorp
 	libcomm
 	;
+
+ Main test_xrl_sockets4_tcp : test_xrl_sockets4_tcp.cc ;
+ LinkLibraries test_xrl_sockets4_tcp :
+	libfea
+	libsocket4userxif
+	libsocket4xif
+	libsocket6userxif
+	libsocket6xif
+	libfindereventnotifierxif
+	libsocketserverbase
+	libtestsocket4
+	libxipc
+	libxorp
+	libcomm
+	;
 } # MAKE_CHECK
 
 InstallBin $(PREFIX)/fea :
Index: fea/xrl_socket_cmds.hh
===================================================================
RCS file: /cvs/xorp/fea/xrl_socket_cmds.hh,v
retrieving revision 1.8
diff -u -r1.8 xrl_socket_cmds.hh
--- fea/xrl_socket_cmds.hh	16 Feb 2007 22:45:53 -0000	1.8
+++ fea/xrl_socket_cmds.hh	26 Mar 2007 12:13:58 -0000
@@ -111,6 +111,7 @@
     A			_src_host;
     uint32_t		_src_port;
     string		_new_sockid;
+    CommandCallback	_cb;
 };
 
 template <typename A>
Index: fea/xrl_socket_server.hh
===================================================================
RCS file: /cvs/xorp/fea/xrl_socket_server.hh,v
retrieving revision 1.12
diff -u -r1.12 xrl_socket_server.hh
--- fea/xrl_socket_server.hh	16 Feb 2007 22:45:54 -0000	1.12
+++ fea/xrl_socket_server.hh	26 Mar 2007 12:14:00 -0000
@@ -92,6 +92,19 @@
     finder_event_observer_0_1_xrl_target_death(const string& clsname,
 					       const string& instance);
 
+    XrlCmdError socket4_0_1_tcp_open(const string&  creator,
+				     const bool&    is_blocking,
+				     string&	    sockid);
+
+    XrlCmdError socket4_0_1_udp_open(const string&  creator,
+				     const bool&    is_blocking,
+				     string&	    sockid);
+
+    XrlCmdError socket4_0_1_bind(const string&	    creator,
+				 const string&	    sockid,
+				 const IPv4&	    local_addr,
+				 const uint32_t&    local_port);
+ 
     XrlCmdError socket4_0_1_tcp_open_and_bind(const string&	creator,
 					      const IPv4&	local_addr,
 					      const uint32_t&	local_port,
@@ -180,6 +193,19 @@
 					      const string&	optname,
 					      uint32_t&		optval);
 
+    XrlCmdError socket6_0_1_tcp_open(const string&  creator,
+				     const bool&    is_blocking,
+				     string&	    sockid);
+
+    XrlCmdError socket6_0_1_udp_open(const string&  creator,
+				     const bool&    is_blocking,
+				     string&	    sockid);
+
+    XrlCmdError socket6_0_1_bind(const string&	    creator,
+				 const string&	    sockid,
+				 const IPv6&	    local_addr,
+				 const uint32_t&    local_port);
+
     XrlCmdError socket6_0_1_tcp_open_and_bind(const string&	creator,
 					      const IPv6&	local_addr,
 					      const uint32_t&	local_port,
@@ -317,6 +343,7 @@
     RemoteSocketOwner* find_or_create_owner(const string& xrl_target_name);
     RemoteSocketOwner* find_owner(const string& xrl_target_name);
     void destroy_owner(const string& xrl_target);
+    template <typename A> void destroy_socket(const string& sockid);
 
     void add_owner_watch(const string& xrl_target_name);
     void add_owner_watch_cb(const XrlError& xe, string xrl_target_name);
@@ -334,6 +361,9 @@
 		     RemoteSocketOwner& rso,
 		     XorpFd		fd,
 		     const A&		addr);
+	RemoteSocket(XrlSocketServer&	ss,
+		     RemoteSocketOwner& rso,
+		     XorpFd		fd);
 	~RemoteSocket();
 
 	inline XorpFd  fd() const			{ return _fd;	      }
@@ -342,6 +372,8 @@
 	inline const RemoteSocketOwner& owner() const	{ return _owner; }
 	inline RemoteSocketOwner& owner()		{ return _owner; }
 
+	void set_addr(const A& addr)			{ _addr(addr); }
+
 	void set_data_recv_enable(bool en);
 	void data_io_cb(XorpFd fd, IoEventType);
 
Index: fea/Makefile.am
===================================================================
RCS file: /cvs/xorp/fea/Makefile.am,v
retrieving revision 1.67
diff -u -r1.67 Makefile.am
--- fea/Makefile.am	23 Aug 2006 17:35:17 -0000	1.67
+++ fea/Makefile.am	26 Mar 2007 12:13:58 -0000
@@ -20,14 +20,17 @@
 check_PROGRAMS 		+= test_mfea
 check_PROGRAMS		+= test_rawsock4
 check_PROGRAMS		+= test_xrl_sockets4_udp
+check_PROGRAMS		+= test_xrl_sockets4_tcp
 
 check_SCRIPTS		 = test_add_route.sh
 check_SCRIPTS		+= test_config_interface.sh
 check_SCRIPTS		+= test_xrl_sockets4_udp.sh
+check_SCRIPTS		+= test_xrl_sockets4_tcp.sh
 
 # -- Test Programs and Scripts
 #TESTS			 = $(check_SCRIPTS)
 TESTS			 = test_xrl_sockets4_udp.sh
+TESTS			+= test_xrl_sockets4_tcp.sh
 TESTS			+= test_rawsock4$(EXEEXT)
 TESTS			+= test_ifmanager_transaction$(EXEEXT)
 
@@ -156,6 +159,20 @@
 test_xrl_sockets4_udp_LDADD	+= $(top_builddir)/libcomm/libcomm.la
 test_xrl_sockets4_udp_LDADD	+= $(top_builddir)/libxorp/libxorp.la
 
+test_xrl_sockets4_tcp_SOURCES	 = test_xrl_sockets4_tcp.cc
+
+test_xrl_sockets4_tcp_LDADD	 = $(noinst_LTLIBRARIES)
+test_xrl_sockets4_tcp_LDADD	+= $(top_builddir)/xrl/interfaces/libsocket4userxif.la
+test_xrl_sockets4_tcp_LDADD	+= $(top_builddir)/xrl/interfaces/libsocket4xif.la
+test_xrl_sockets4_tcp_LDADD	+= $(top_builddir)/xrl/interfaces/libsocket6userxif.la
+test_xrl_sockets4_tcp_LDADD	+= $(top_builddir)/xrl/interfaces/libsocket6xif.la
+test_xrl_sockets4_tcp_LDADD	+= $(top_builddir)/xrl/interfaces/libfindereventnotifierxif.la
+test_xrl_sockets4_tcp_LDADD	+= $(top_builddir)/xrl/targets/libsocketserverbase.la
+test_xrl_sockets4_tcp_LDADD	+= $(top_builddir)/xrl/targets/libtestsocket4.la
+test_xrl_sockets4_tcp_LDADD	+= $(top_builddir)/libxipc/libxipc.la
+test_xrl_sockets4_tcp_LDADD	+= $(top_builddir)/libcomm/libcomm.la
+test_xrl_sockets4_tcp_LDADD	+= $(top_builddir)/libxorp/libxorp.la
+
 # -- Sources and Linkage for demo_fea_ifmgr_client
 demo_fea_ifmgr_client_SOURCES	 = demo_fea_ifmgr_client.cc
 demo_fea_ifmgr_client_LDADD	 = $(top_builddir)/xrl/targets/libdemofeaifmgrclientbase.la
Index: fea/xrl_socket_server.cc
===================================================================
RCS file: /cvs/xorp/fea/xrl_socket_server.cc,v
retrieving revision 1.29
diff -u -r1.29 xrl_socket_server.cc
--- fea/xrl_socket_server.cc	16 Feb 2007 22:45:53 -0000	1.29
+++ fea/xrl_socket_server.cc	26 Mar 2007 12:14:00 -0000
@@ -57,7 +57,7 @@
 		       uint16_t		finder_port,
 		       XrlSocketServer* parent)
 	: XrlStdRouter(eventloop, class_name, finder_host, finder_port),
-	  _p(parent)
+	    _p(parent)
     {}
 
     void
@@ -138,7 +138,7 @@
 					XrlSender&		xs,
 					const string&		tname)
     : XrlSocketCommandDispatcher(xs), _ss(ss), _tname(tname), _sockets(0),
-      _watched(false)
+	_watched(false)
 {
     _ss.add_owner_watch(_tname);
 }
@@ -163,7 +163,8 @@
     _sockets--;
 
     // Arrange for instance to be cleared up if no xrls are pending
-    if (queue_empty())
+    // (and there are no remaining sockets [tschooley])
+    if (queue_empty() && _sockets == 0)
 	_ss.destroy_owner(_tname);
 }
 
@@ -192,7 +193,8 @@
 	return &i->second;
     }
     pair<map<string, RemoteSocketOwner>::iterator, bool> ins =
-	_socket_owners.insert(pair<string,RemoteSocketOwner>(target, RemoteSocketOwner(*this, *_r, target)));
+	_socket_owners.insert(pair<string,RemoteSocketOwner>(target, 
+				RemoteSocketOwner(*this, *_r, target)));
     if (ins.second == false)
 	return 0;
     i = ins.first;
@@ -213,10 +215,48 @@
 {
     map<string, RemoteSocketOwner>::iterator i = _socket_owners.find(target);
     if (i != _socket_owners.end()) {
+    /*
+     * remove_sockets_owned_by(target) needs to be called before the owner
+     * is destroyed, otherwise remove_owner_watch (which calls 
+     * remove_sockets_owned_by at an arbitrary future time) might find
+     * RemoteSockets with their owners destroyed, thus any owner() accesses
+     * will cause a segfault. [tschooley]
+     */
+    remove_sockets_owned_by(target);
 	_socket_owners.erase(i);
     }
 }
 
+template <>
+void
+XrlSocketServer::destroy_socket<IPv4>(const string& sockid)
+{
+    V4Sockets::iterator i4 = _v4sockets.begin();
+    while (i4 != _v4sockets.end()) {
+	RemoteSocket<IPv4>* rs = i4->get();
+	if (rs->sockid() == sockid) {
+	    _v4sockets.erase(i4);
+	    return;
+	}
+	i4++;
+    }
+}
+
+template <>
+void
+XrlSocketServer::destroy_socket<IPv6>(const string& sockid)
+{
+    V6Sockets::iterator i6 = _v6sockets.begin();
+    while (i6 != _v6sockets.end()) {
+	RemoteSocket<IPv6>* rs = i6->get();
+	if (rs->sockid() == sockid) {
+	    _v6sockets.erase(i6);
+	    return;
+	}
+	i6++;
+    }
+}
+
 void
 XrlSocketServer::add_owner_watch(const string& target)
 {
@@ -269,9 +309,9 @@
     }
     RemoteSocketOwner* rso = find_owner(target);
     if (rso) {
+    XLOG_ASSERT(rso->socket_count() == 0);
 	rso->set_watched(false);
     }
-    remove_sockets_owned_by(target);
     XLOG_ASSERT(find_owner(target) == 0);
 }
 
@@ -314,6 +354,15 @@
 }
 
 template <typename A>
+XrlSocketServer::RemoteSocket<A>::RemoteSocket(XrlSocketServer&	ss,
+			      RemoteSocketOwner&		owner,
+			      XorpFd				fd)
+    : _ss(ss), _owner(owner), _fd(fd), _addr(A()), _sockid(XUID().str())
+{
+    _owner.incr_socket_count();
+}
+
+template <typename A>
 XrlSocketServer::RemoteSocket<A>::~RemoteSocket()
 {
     EventLoop& eventloop = _ss.eventloop();
@@ -352,15 +401,14 @@
     SocketUserSendRecvEvent<A>* cmd =
 	new SocketUserSendRecvEvent<A>(owner().tgt_name(), sockid());
 
-    typename A::SockAddrType sin;
-    socklen_t sin_len = sizeof(sin);
-    sockaddr* sa = reinterpret_cast<sockaddr*>(&sin);
+    struct sockaddr_storage ss;
+    socklen_t ss_len = sizeof(ss);
 
     // XXX buffer is overprovisioned for normal case and size hard-coded...
     // It get's resized a little later on to amount of data read.
     cmd->data().resize(64000);
     ssize_t rsz = recvfrom(fd, XORP_BUF_CAST(&cmd->data()[0]),
-			   cmd->data().size(), 0, sa, &sin_len);
+	cmd->data().size(), 0, (struct sockaddr *)&ss, &ss_len);
 
     if (rsz < 0) {
 	delete cmd;
@@ -373,8 +421,57 @@
 
     cmd->data().resize(rsz);
 
-    XLOG_ASSERT(sa->sa_family == A::af());
-    cmd->set_source(sin, sin_len);
+    // Establish socket type
+    int so_type = comm_sock_get_type(fd);
+
+    if (so_type == SOCK_DGRAM)
+    {
+	XLOG_ASSERT(ss.ss_family == A::af());
+	typename A::SockAddrType *sa =
+	    reinterpret_cast<typename A::SockAddrType *>(&ss);
+	socklen_t sa_len = sizeof(*sa);
+	cmd->set_source(*sa, sa_len);
+    }
+    else if (so_type == SOCK_STREAM)
+    {
+	if (rsz == 0) {
+	    /* socket closed, need to call deletion of self */
+	    delete cmd;
+	    ref_ptr<XrlSocketCommandBase> cmd = new
+		SocketUserSendCloseEvent<A>(owner().tgt_name(),
+		    sockid(), "Remote host closed the connection.");
+	    owner().enqueue(cmd);
+	    return _ss.destroy_socket<A>(sockid());
+	}
+
+	struct sockaddr_storage newss;
+	socklen_t newss_len = sizeof(newss);
+
+	int error = getpeername(fd, (struct sockaddr *)&newss, &newss_len);
+	if (error != 0) {
+	    ref_ptr<XrlSocketCommandBase> ecmd = new
+		SocketUserSendErrorEvent<A>(owner().tgt_name(), sockid(),
+					comm_get_last_error_str(), false);
+		owner().enqueue(ecmd);
+		return;
+	}
+	XLOG_ASSERT(newss.ss_family == A::af());
+	typename A::SockAddrType *sa =
+	    reinterpret_cast<typename A::SockAddrType *>(&newss);
+	socklen_t sa_len = sizeof(*sa);
+	cmd->set_source(*sa, sa_len);
+    }
+    else
+    {
+	delete cmd;
+	string error = "Invalid socket type %d\n", so_type;
+	ref_ptr<XrlSocketCommandBase> ecmd = new
+	    SocketUserSendErrorEvent<A>(owner().tgt_name(),
+					sockid(), error, false);
+	owner().enqueue(ecmd);
+	return;
+    }
+
     debug_msg("Command %s\n", cmd->str().c_str());
     owner().enqueue(cmd);
 }
@@ -385,7 +482,7 @@
 {
     EventLoop& eventloop = _ss.eventloop();
     if (en) {
-	eventloop.remove_ioevent_cb(_fd, IOT_ACCEPT,
+	eventloop.add_ioevent_cb(_fd, IOT_ACCEPT,
 			  callback(this, &RemoteSocket::accept_io_cb));
     } else {
 	eventloop.remove_ioevent_cb(_fd);
@@ -398,37 +495,38 @@
 {
     XLOG_ASSERT(fd == _fd);
 
-    struct sockaddr_storage sa;
-    socklen_t sa_len = sizeof(sa);
-
     XorpFd afd = comm_sock_accept(_fd);
     if (!afd.is_valid()) {
-	ref_ptr<XrlSocketCommandBase*> ecmd = new
-	    SocketUserSendErrorEvent<A>(owner()->tgt_name(), sockid(),
+	ref_ptr<XrlSocketCommandBase> ecmd = new
+	    SocketUserSendErrorEvent<A>(owner().tgt_name(), sockid(),
 					comm_get_last_error_str(), false);
 	owner().enqueue(ecmd);
 	return;
     }
 
-    // XXX
-    int error = getpeername(afd, (struct sockaddr *)&sa, &sa_len);
+    struct sockaddr_storage ss;
+    socklen_t ss_len = sizeof(ss);
+
+    int error = getpeername(afd, (struct sockaddr *)&ss, &ss_len);
     if (error != 0) {
-	ref_ptr<XrlSocketCommandBase*> ecmd = new
-	    SocketUserSendErrorEvent<A>(owner()->tgt_name(), sockid(),
+	ref_ptr<XrlSocketCommandBase> ecmd = new
+	    SocketUserSendErrorEvent<A>(owner().tgt_name(), sockid(),
 					comm_get_last_error_str(), false);
 	owner().enqueue(ecmd);
 	return;
     }
 
-    XLOG_ASSERT(sa.ss_family == A::af());
-
-    _ss.push_socket(new RemoteSocket<A>(_ss, owner(), afd, sa));
-
-    ref_ptr<XrlSocketCommandBase*> cmd =
+    XLOG_ASSERT(ss.ss_family == A::af());
+    sockaddr* sa = reinterpret_cast<sockaddr*>(&ss);
+    A host(*sa);
+
+    _ss.push_socket(new RemoteSocket<A>(_ss, owner(), afd, host));
+    
+    ref_ptr<XrlSocketCommandBase> cmd =
 	new SocketUserSendConnectEvent<A>(&_ss, _owner.tgt_name(),
-					  _sockid, sa,
-					  sockaddr_ip_port<A>(sa),
-					  _v4sockets.back()->sockid());
+					  _sockid, host,
+					  sockaddr_ip_port<A>(*sa), 
+					  _ss._v4sockets.back()->sockid());
     owner().enqueue(cmd);
 }
 
@@ -657,6 +755,83 @@
 }
 
 XrlCmdError
+XrlSocketServer::socket4_0_1_tcp_open(const string&	creator,
+				      const bool&	is_blocking,
+				      string&		sockid)
+{
+    if (status() != SERVICE_RUNNING)
+	return XrlCmdError::COMMAND_FAILED(NOT_RUNNING_MSG);
+
+    XorpFd fd = comm_open_tcp(AF_INET, is_blocking);
+    if (!fd.is_valid()) {
+	return XrlCmdError::COMMAND_FAILED(last_comm_error());
+    }
+
+    RemoteSocketOwner* rso = find_or_create_owner(creator);
+    if (rso == 0) {
+	comm_close(fd);
+	return XrlCmdError::COMMAND_FAILED("Could not create owner");
+    }
+    _v4sockets.push_back(new RemoteSocket<IPv4>(*this, *rso, fd));
+    sockid = _v4sockets.back()->sockid();
+
+    return XrlCmdError::OKAY();
+}
+
+XrlCmdError
+XrlSocketServer::socket4_0_1_udp_open(const string&	creator,
+				      const bool&	is_blocking,
+				      string&		sockid)
+{
+    if (status() != SERVICE_RUNNING)
+	return XrlCmdError::COMMAND_FAILED(NOT_RUNNING_MSG);
+
+    XorpFd fd = comm_open_udp(AF_INET, is_blocking);
+    if (!fd.is_valid()) {
+	return XrlCmdError::COMMAND_FAILED(last_comm_error());
+    }
+
+    RemoteSocketOwner* rso = find_or_create_owner(creator);
+    if (rso == 0) {
+	comm_close(fd);
+	return XrlCmdError::COMMAND_FAILED("Could not create owner");
+    }
+    _v4sockets.push_back(new RemoteSocket<IPv4>(*this, *rso, fd));
+    sockid = _v4sockets.back()->sockid();
+
+    return XrlCmdError::OKAY();
+}
+
+XrlCmdError
+XrlSocketServer::socket4_0_1_bind(const string&	    creator,
+				  const string&	    sockid,
+				  const IPv4&	    local_addr,
+				  const uint32_t&   local_port)
+{
+    if (status() != SERVICE_RUNNING)
+	return XrlCmdError::COMMAND_FAILED(NOT_RUNNING_MSG);
+    
+    UNUSED(creator); // May use it in future using lookups via owner
+
+    in_addr ia;
+    local_addr.copy_out(ia);
+
+    V4Sockets::const_iterator ci;
+    for (ci = _v4sockets.begin(); ci != _v4sockets.end(); ++ci) {
+	RemoteSocket<IPv4>* rs = ci->get();
+	if (rs->sockid() == sockid) {
+	    int x = comm_sock_bind4(rs->fd(), &ia, htons(local_port));
+	    //rs->set_connect_recv_enable(true);
+	    if (x == XORP_OK) {
+		return XrlCmdError::OKAY();
+	    }
+	    return XrlCmdError::COMMAND_FAILED(strerror(errno));
+	}
+    }
+    return XrlCmdError::COMMAND_FAILED(NOT_FOUND_MSG);
+}
+
+XrlCmdError
 XrlSocketServer::socket4_0_1_tcp_open_and_bind(const string&	creator,
 					       const IPv4&	local_addr,
 					       const uint32_t&	local_port,
@@ -758,7 +933,7 @@
     mcast_addr.copy_out(grp);
 
     XorpFd fd = comm_bind_join_udp4(&grp, &ia, htons(local_port), reuse,
-				 is_blocking);
+				    is_blocking);
     if (fd <= 0) {
 	return XrlCmdError::COMMAND_FAILED(last_comm_error());
     }
@@ -990,6 +1165,7 @@
 	RemoteSocket<IPv4>* rs = ci->get();
 	if (rs->sockid() == sockid) {
 	    int x = listen(rs->fd(), backlog);
+	    rs->set_connect_recv_enable(true);
 	    if (x == 0) {
 		return XrlCmdError::OKAY();
 	    }
@@ -999,7 +1175,6 @@
     return XrlCmdError::COMMAND_FAILED(NOT_FOUND_MSG);
 }
 
-
 XrlCmdError
 XrlSocketServer::socket4_0_1_send(
     const string&		sockid,
@@ -1311,6 +1486,83 @@
 // socket6/0.1 implementation
 
 XrlCmdError
+XrlSocketServer::socket6_0_1_tcp_open(const string&	creator,
+				      const bool&	is_blocking,
+				      string&		sockid)
+{
+    if (status() != SERVICE_RUNNING)
+	return XrlCmdError::COMMAND_FAILED(NOT_RUNNING_MSG);
+
+    XorpFd fd = comm_open_tcp(AF_INET, is_blocking);
+    if (!fd.is_valid()) {
+	return XrlCmdError::COMMAND_FAILED(last_comm_error());
+    }
+
+    RemoteSocketOwner* rso = find_or_create_owner(creator);
+    if (rso == 0) {
+	comm_close(fd);
+	return XrlCmdError::COMMAND_FAILED("Could not create owner");
+    }
+    _v6sockets.push_back(new RemoteSocket<IPv6>(*this, *rso, fd));
+    sockid = _v6sockets.back()->sockid();
+
+    return XrlCmdError::OKAY();
+}
+
+XrlCmdError
+XrlSocketServer::socket6_0_1_udp_open(const string&	creator,
+				      const bool&	is_blocking,
+				      string&		sockid)
+{
+    if (status() != SERVICE_RUNNING)
+	return XrlCmdError::COMMAND_FAILED(NOT_RUNNING_MSG);
+
+    XorpFd fd = comm_open_udp(AF_INET6, is_blocking);
+    if (!fd.is_valid()) {
+	return XrlCmdError::COMMAND_FAILED(last_comm_error());
+    }
+
+    RemoteSocketOwner* rso = find_or_create_owner(creator);
+    if (rso == 0) {
+	comm_close(fd);
+	return XrlCmdError::COMMAND_FAILED("Could not create owner");
+    }
+    _v6sockets.push_back(new RemoteSocket<IPv6>(*this, *rso, fd));
+    sockid = _v6sockets.back()->sockid();
+
+    return XrlCmdError::OKAY();
+}
+
+XrlCmdError
+XrlSocketServer::socket6_0_1_bind(const string&	    creator,
+				  const string&	    sockid,
+				  const IPv6&	    local_addr,
+				  const uint32_t&   local_port)
+{
+    if (status() != SERVICE_RUNNING)
+	return XrlCmdError::COMMAND_FAILED(NOT_RUNNING_MSG);
+    
+    UNUSED(creator); // May use it in future using lookups via owner
+
+    in6_addr ia;
+    local_addr.copy_out(ia);
+    
+    V6Sockets::const_iterator ci;
+    for (ci = _v6sockets.begin(); ci != _v6sockets.end(); ++ci) {
+	RemoteSocket<IPv6>* rs = ci->get();
+	if (rs->sockid() == sockid) {
+	    int x = comm_sock_bind6(rs->fd(), &ia, htons(local_port));
+	    //rs->set_connect_recv_enable(true);
+	    if (x == XORP_OK) {
+		return XrlCmdError::OKAY();
+	    }
+	    return XrlCmdError::COMMAND_FAILED(strerror(errno));
+	}
+    }
+    return XrlCmdError::COMMAND_FAILED(NOT_FOUND_MSG);
+}
+
+XrlCmdError
 XrlSocketServer::socket6_0_1_tcp_open_and_bind(const string&	creator,
 					       const IPv6&	local_addr,
 					       const uint32_t&	local_port,
@@ -1674,8 +1926,8 @@
     for (ci = _v6sockets.begin(); ci != _v6sockets.end(); ++ci) {
 	RemoteSocket<IPv6>* rs = ci->get();
 	if (rs->sockid() == sockid) {
-	    int x = listen(rs->fd(), backlog);
-	    if (x == 0) {
+	    if (comm_listen(rs->fd(), backlog) == XORP_OK) {
+		rs->set_connect_recv_enable(true);
 		return XrlCmdError::OKAY();
 	    }
 	    return XrlCmdError::COMMAND_FAILED(strerror(errno));
Index: xrl/interfaces/socket6_xif.hh
===================================================================
RCS file: /cvs/xorp/xrl/interfaces/socket6_xif.hh,v
retrieving revision 1.9
diff -u -r1.9 socket6_xif.hh
--- xrl/interfaces/socket6_xif.hh	16 Feb 2007 22:47:45 -0000	1.9
+++ xrl/interfaces/socket6_xif.hh	26 Mar 2007 12:14:02 -0000
@@ -28,24 +28,37 @@
     XrlSocket6V0p1Client(XrlSender* s) : _sender(s) {}
     virtual ~XrlSocket6V0p1Client() {}
 
+    typedef XorpCallback2<void, const XrlError&, const string*>::RefPtr TcpOpenCB;
+
+    bool send_tcp_open(
+	const char*	dst_xrl_target_name,
+	const string&	creator,
+	const bool&	is_blocking,
+	const TcpOpenCB&	cb
+    );
+
+    typedef XorpCallback2<void, const XrlError&, const string*>::RefPtr UdpOpenCB;
+
+    bool send_udp_open(
+	const char*	dst_xrl_target_name,
+	const string&	creator,
+	const bool&	is_blocking,
+	const UdpOpenCB&	cb
+    );
+
+    typedef XorpCallback1<void, const XrlError&>::RefPtr BindCB;
+
+    bool send_bind(
+	const char*	dst_xrl_target_name,
+	const string&	creator,
+	const string&	sockid,
+	const IPv6&	local_addr,
+	const uint32_t&	local_port,
+	const BindCB&	cb
+    );
+
     typedef XorpCallback2<void, const XrlError&, const string*>::RefPtr TcpOpenAndBindCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Create a bound TCP socket.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param creator the Xrl Target instance name of the socket creator. The
-     *  named target must implement socket6_user/0.1.
-     *
-     *  @param local_addr the interface address to bind socket to.
-     *
-     *  @param local_port the port to bind socket to.
-     *
-     *  @param is_blocking if true then the socket will be blocking, otherwise
-     *  non-blocking.
-     */
+
     bool send_tcp_open_and_bind(
 	const char*	dst_xrl_target_name,
 	const string&	creator,
@@ -56,23 +69,7 @@
     );
 
     typedef XorpCallback2<void, const XrlError&, const string*>::RefPtr UdpOpenAndBindCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Create a bound UDP socket.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param creator the Xrl Target instance name of the socket creator. The
-     *  named target must implement socket6_user/0.1.
-     *
-     *  @param local_addr the interface address to bind socket to.
-     *
-     *  @param local_port the port to bind socket to.
-     *
-     *  @param is_blocking if true then the socket will be blocking, otherwise
-     *  non-blocking.
-     */
+
     bool send_udp_open_and_bind(
 	const char*	dst_xrl_target_name,
 	const string&	creator,
@@ -83,29 +80,7 @@
     );
 
     typedef XorpCallback2<void, const XrlError&, const string*>::RefPtr UdpOpenBindJoinCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Create a bound UDP multicast socket.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param creator the Xrl Target instance name of the socket creator. The
-     *  named target must implement socket6_user/0.1.
-     *
-     *  @param local_addr the interface address to bind socket to.
-     *
-     *  @param local_port the port to bind socket to.
-     *
-     *  @param mcast_addr the multicast group address to join.
-     *
-     *  @param ttl the ttl to use for this multicast socket.
-     *
-     *  @param reuse allow other sockets to bind to same multicast group.
-     *
-     *  @param is_blocking if true then the socket will be blocking, otherwise
-     *  non-blocking.
-     */
+
     bool send_udp_open_bind_join(
 	const char*	dst_xrl_target_name,
 	const string&	creator,
@@ -119,27 +94,7 @@
     );
 
     typedef XorpCallback2<void, const XrlError&, const string*>::RefPtr TcpOpenBindConnectCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Create a bound and connected TCP socket.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param creator the Xrl Target instance name of the socket creator. The
-     *  named target must implement socket6_user/0.1.
-     *
-     *  @param local_addr the interface address to bind socket to.
-     *
-     *  @param local_port the port to bind socket to.
-     *
-     *  @param remote_addr the address to connect to.
-     *
-     *  @param remote_port the remote port to connect to.
-     *
-     *  @param is_blocking if true then the socket will be blocking, otherwise
-     *  non-blocking.
-     */
+
     bool send_tcp_open_bind_connect(
 	const char*	dst_xrl_target_name,
 	const string&	creator,
@@ -152,27 +107,7 @@
     );
 
     typedef XorpCallback2<void, const XrlError&, const string*>::RefPtr UdpOpenBindConnectCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Create a bound and connected UDP socket.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param creator the Xrl Target instance name of the socket creator. The
-     *  named target must implement socket6_user/0.1.
-     *
-     *  @param local_addr the interface address to bind socket to.
-     *
-     *  @param local_port the port to bind socket to.
-     *
-     *  @param remote_addr the address to connect to.
-     *
-     *  @param remote_port the remote port to connect to.
-     *
-     *  @param is_blocking if true then the socket will be blocking, otherwise
-     *  non-blocking.
-     */
+
     bool send_udp_open_bind_connect(
 	const char*	dst_xrl_target_name,
 	const string&	creator,
@@ -185,19 +120,7 @@
     );
 
     typedef XorpCallback1<void, const XrlError&>::RefPtr UdpJoinGroupCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Join multicast group on already bound socket.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param sockid unique socket id.
-     *
-     *  @param mcast_addr group to join.
-     *
-     *  @param join_if_addr interface address to perform join on.
-     */
+
     bool send_udp_join_group(
 	const char*	dst_xrl_target_name,
 	const string&	sockid,
@@ -207,19 +130,7 @@
     );
 
     typedef XorpCallback1<void, const XrlError&>::RefPtr UdpLeaveGroupCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Leave multicast group on already bound socket.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param sockid unique socket id.
-     *
-     *  @param mcast_addr group to leave.
-     *
-     *  @param leave_if_addr interface address to perform leave on.
-     */
+
     bool send_udp_leave_group(
 	const char*	dst_xrl_target_name,
 	const string&	sockid,
@@ -229,15 +140,7 @@
     );
 
     typedef XorpCallback1<void, const XrlError&>::RefPtr CloseCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Close socket.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param sockid unique socket id of socket to be closed.
-     */
+
     bool send_close(
 	const char*	dst_xrl_target_name,
 	const string&	sockid,
@@ -245,19 +148,7 @@
     );
 
     typedef XorpCallback1<void, const XrlError&>::RefPtr TcpListenCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Listen for inbound connections on socket. When a connection request
-     *  received the socket creator will receive notification through
-     *  socket6_user/0.1/connect_event.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param sockid the unique socket id of the socket to perform listen.
-     *
-     *  @param backlog the maximum number of pending connections.
-     */
+
     bool send_tcp_listen(
 	const char*	dst_xrl_target_name,
 	const string&	sockid,
@@ -266,17 +157,7 @@
     );
 
     typedef XorpCallback1<void, const XrlError&>::RefPtr SendCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Send data on socket.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param sockid unique socket id.
-     *
-     *  @param data block of data to be sent.
-     */
+
     bool send_send(
 	const char*	dst_xrl_target_name,
 	const string&	sockid,
@@ -285,27 +166,7 @@
     );
 
     typedef XorpCallback1<void, const XrlError&>::RefPtr SendWithFlagsCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Send data on socket with optional flags. These flags provide hints to
-     *  the forwarding engine on how to send the packets, they are not
-     *  guaranteed to work. NB: There is no flag for "do not route" as this is
-     *  always true since the particular forwarding engine sending the data may
-     *  not have access to the full routing table.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param sockid unique socket id.
-     *
-     *  @param data block of data to be sent.
-     *
-     *  @param out_of_band mark data as out of band.
-     *
-     *  @param end_of_record data completes record.
-     *
-     *  @param end_of_file data completes file.
-     */
+
     bool send_send_with_flags(
 	const char*	dst_xrl_target_name,
 	const string&	sockid,
@@ -317,23 +178,7 @@
     );
 
     typedef XorpCallback1<void, const XrlError&>::RefPtr SendToCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Send data on socket to a given destination. The packet is not routed as
-     *  the forwarding engine sending the packet may not have access to the
-     *  full routing table.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param sockid unique socket id.
-     *
-     *  @param remote_addr destination address for data.
-     *
-     *  @param remote_port destination port for data.
-     *
-     *  @param data block of data to be sent.
-     */
+
     bool send_send_to(
 	const char*	dst_xrl_target_name,
 	const string&	sockid,
@@ -344,29 +189,7 @@
     );
 
     typedef XorpCallback1<void, const XrlError&>::RefPtr SendToWithFlagsCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Send data on socket to a given destination. The packet is not routed as
-     *  the forwarding engine sending the packet may not have access to the
-     *  full routing table.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param sockid unique socket id.
-     *
-     *  @param remote_addr destination address for data.
-     *
-     *  @param remote_port destination port for data.
-     *
-     *  @param data block of data to be sent.
-     *
-     *  @param out_of_band mark data as out of band.
-     *
-     *  @param end_of_record data completes record.
-     *
-     *  @param end_of_file data completes file.
-     */
+
     bool send_send_to_with_flags(
 	const char*	dst_xrl_target_name,
 	const string&	sockid,
@@ -380,21 +203,7 @@
     );
 
     typedef XorpCallback1<void, const XrlError&>::RefPtr SendFromMulticastIfCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Send data on socket to a given multicast group from a given interface.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param sockid unique socket id.
-     *
-     *  @param group_addr destination address for data.
-     *
-     *  @param group_port destination port for data.
-     *
-     *  @param ifaddr interface address
-     */
+
     bool send_send_from_multicast_if(
 	const char*	dst_xrl_target_name,
 	const string&	sockid,
@@ -406,21 +215,7 @@
     );
 
     typedef XorpCallback1<void, const XrlError&>::RefPtr SetSocketOptionCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Set a named socket option.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param sockid unique socket id.
-     *
-     *  @param optname name of option to be set. Valid values are:
-     *  "multicast_loopback" "multicast_hops"
-     *
-     *  @param optval value of option to be set. If value is logically boolean
-     *  then zero represents false and any non-zero value true.
-     */
+
     bool send_set_socket_option(
 	const char*	dst_xrl_target_name,
 	const string&	sockid,
@@ -430,18 +225,7 @@
     );
 
     typedef XorpCallback2<void, const XrlError&, const uint32_t*>::RefPtr GetSocketOptionCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Get a named socket option.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param sockid unique socket id.
-     *
-     *  @param optname name of option to be set. Valid values are documented in
-     *  set_socket_option.
-     */
+
     bool send_get_socket_option(
 	const char*	dst_xrl_target_name,
 	const string&	sockid,
@@ -453,6 +237,24 @@
     XrlSender* _sender;
 
 private:
+    void unmarshall_tcp_open(
+	const XrlError&	e,
+	XrlArgs*	a,
+	TcpOpenCB		cb
+    );
+
+    void unmarshall_udp_open(
+	const XrlError&	e,
+	XrlArgs*	a,
+	UdpOpenCB		cb
+    );
+
+    void unmarshall_bind(
+	const XrlError&	e,
+	XrlArgs*	a,
+	BindCB		cb
+    );
+
     void unmarshall_tcp_open_and_bind(
 	const XrlError&	e,
 	XrlArgs*	a,
Index: xrl/interfaces/socket4_xif.cc
===================================================================
RCS file: /cvs/xorp/xrl/interfaces/socket4_xif.cc,v
retrieving revision 1.13
diff -u -r1.13 socket4_xif.cc
--- xrl/interfaces/socket4_xif.cc	16 Feb 2007 22:47:44 -0000	1.13
+++ xrl/interfaces/socket4_xif.cc	26 Mar 2007 12:14:02 -0000
@@ -12,6 +12,128 @@
 #include "socket4_xif.hh"
 
 bool
+XrlSocket4V0p1Client::send_tcp_open(
+	const char*	dst_xrl_target_name,
+	const string&	creator,
+	const bool&	is_blocking,
+	const TcpOpenCB&	cb
+)
+{
+    Xrl x(dst_xrl_target_name, "socket4/0.1/tcp_open");
+    x.args().add("creator", creator);
+    x.args().add("is_blocking", is_blocking);
+    return _sender->send(x, callback(this, &XrlSocket4V0p1Client::unmarshall_tcp_open, cb));
+}
+
+
+/* Unmarshall tcp_open */
+void
+XrlSocket4V0p1Client::unmarshall_tcp_open(
+	const XrlError&	e,
+	XrlArgs*	a,
+	TcpOpenCB		cb
+)
+{
+    if (e != XrlError::OKAY()) {
+	cb->dispatch(e, 0);
+	return;
+    } else if (a && a->size() != 1) {
+	XLOG_ERROR("Wrong number of arguments (%u != %u)", XORP_UINT_CAST(a->size()), XORP_UINT_CAST(1));
+	cb->dispatch(XrlError::BAD_ARGS(), 0);
+	return;
+    }
+    string sockid;
+    try {
+	a->get("sockid", sockid);
+    } catch (const XrlArgs::XrlAtomNotFound&) {
+	XLOG_ERROR("Atom not found");
+	cb->dispatch(XrlError::BAD_ARGS(), 0);
+	return;
+    }
+    cb->dispatch(e, &sockid);
+}
+
+bool
+XrlSocket4V0p1Client::send_udp_open(
+	const char*	dst_xrl_target_name,
+	const string&	creator,
+	const bool&	is_blocking,
+	const UdpOpenCB&	cb
+)
+{
+    Xrl x(dst_xrl_target_name, "socket4/0.1/udp_open");
+    x.args().add("creator", creator);
+    x.args().add("is_blocking", is_blocking);
+    return _sender->send(x, callback(this, &XrlSocket4V0p1Client::unmarshall_udp_open, cb));
+}
+
+
+/* Unmarshall udp_open */
+void
+XrlSocket4V0p1Client::unmarshall_udp_open(
+	const XrlError&	e,
+	XrlArgs*	a,
+	UdpOpenCB		cb
+)
+{
+    if (e != XrlError::OKAY()) {
+	cb->dispatch(e, 0);
+	return;
+    } else if (a && a->size() != 1) {
+	XLOG_ERROR("Wrong number of arguments (%u != %u)", XORP_UINT_CAST(a->size()), XORP_UINT_CAST(1));
+	cb->dispatch(XrlError::BAD_ARGS(), 0);
+	return;
+    }
+    string sockid;
+    try {
+	a->get("sockid", sockid);
+    } catch (const XrlArgs::XrlAtomNotFound&) {
+	XLOG_ERROR("Atom not found");
+	cb->dispatch(XrlError::BAD_ARGS(), 0);
+	return;
+    }
+    cb->dispatch(e, &sockid);
+}
+
+bool
+XrlSocket4V0p1Client::send_bind(
+	const char*	dst_xrl_target_name,
+	const string&	creator,
+	const string&	sockid,
+	const IPv4&	local_addr,
+	const uint32_t&	local_port,
+	const BindCB&	cb
+)
+{
+    Xrl x(dst_xrl_target_name, "socket4/0.1/bind");
+    x.args().add("creator", creator);
+    x.args().add("sockid", sockid);
+    x.args().add("local_addr", local_addr);
+    x.args().add("local_port", local_port);
+    return _sender->send(x, callback(this, &XrlSocket4V0p1Client::unmarshall_bind, cb));
+}
+
+
+/* Unmarshall bind */
+void
+XrlSocket4V0p1Client::unmarshall_bind(
+	const XrlError&	e,
+	XrlArgs*	a,
+	BindCB		cb
+)
+{
+    if (e != XrlError::OKAY()) {
+	cb->dispatch(e);
+	return;
+    } else if (a && a->size() != 0) {
+	XLOG_ERROR("Wrong number of arguments (%u != %u)", XORP_UINT_CAST(a->size()), XORP_UINT_CAST(0));
+	cb->dispatch(XrlError::BAD_ARGS());
+	return;
+    }
+    cb->dispatch(e);
+}
+
+bool
 XrlSocket4V0p1Client::send_tcp_open_and_bind(
 	const char*	dst_xrl_target_name,
 	const string&	creator,
Index: xrl/interfaces/socket6_xif.cc
===================================================================
RCS file: /cvs/xorp/xrl/interfaces/socket6_xif.cc,v
retrieving revision 1.11
diff -u -r1.11 socket6_xif.cc
--- xrl/interfaces/socket6_xif.cc	16 Feb 2007 22:47:44 -0000	1.11
+++ xrl/interfaces/socket6_xif.cc	26 Mar 2007 12:14:02 -0000
@@ -12,6 +12,128 @@
 #include "socket6_xif.hh"
 
 bool
+XrlSocket6V0p1Client::send_tcp_open(
+	const char*	dst_xrl_target_name,
+	const string&	creator,
+	const bool&	is_blocking,
+	const TcpOpenCB&	cb
+)
+{
+    Xrl x(dst_xrl_target_name, "socket6/0.1/tcp_open");
+    x.args().add("creator", creator);
+    x.args().add("is_blocking", is_blocking);
+    return _sender->send(x, callback(this, &XrlSocket6V0p1Client::unmarshall_tcp_open, cb));
+}
+
+
+/* Unmarshall tcp_open */
+void
+XrlSocket6V0p1Client::unmarshall_tcp_open(
+	const XrlError&	e,
+	XrlArgs*	a,
+	TcpOpenCB		cb
+)
+{
+    if (e != XrlError::OKAY()) {
+	cb->dispatch(e, 0);
+	return;
+    } else if (a && a->size() != 1) {
+	XLOG_ERROR("Wrong number of arguments (%u != %u)", XORP_UINT_CAST(a->size()), XORP_UINT_CAST(1));
+	cb->dispatch(XrlError::BAD_ARGS(), 0);
+	return;
+    }
+    string sockid;
+    try {
+	a->get("sockid", sockid);
+    } catch (const XrlArgs::XrlAtomNotFound&) {
+	XLOG_ERROR("Atom not found");
+	cb->dispatch(XrlError::BAD_ARGS(), 0);
+	return;
+    }
+    cb->dispatch(e, &sockid);
+}
+
+bool
+XrlSocket6V0p1Client::send_udp_open(
+	const char*	dst_xrl_target_name,
+	const string&	creator,
+	const bool&	is_blocking,
+	const UdpOpenCB&	cb
+)
+{
+    Xrl x(dst_xrl_target_name, "socket6/0.1/udp_open");
+    x.args().add("creator", creator);
+    x.args().add("is_blocking", is_blocking);
+    return _sender->send(x, callback(this, &XrlSocket6V0p1Client::unmarshall_udp_open, cb));
+}
+
+
+/* Unmarshall udp_open */
+void
+XrlSocket6V0p1Client::unmarshall_udp_open(
+	const XrlError&	e,
+	XrlArgs*	a,
+	UdpOpenCB		cb
+)
+{
+    if (e != XrlError::OKAY()) {
+	cb->dispatch(e, 0);
+	return;
+    } else if (a && a->size() != 1) {
+	XLOG_ERROR("Wrong number of arguments (%u != %u)", XORP_UINT_CAST(a->size()), XORP_UINT_CAST(1));
+	cb->dispatch(XrlError::BAD_ARGS(), 0);
+	return;
+    }
+    string sockid;
+    try {
+	a->get("sockid", sockid);
+    } catch (const XrlArgs::XrlAtomNotFound&) {
+	XLOG_ERROR("Atom not found");
+	cb->dispatch(XrlError::BAD_ARGS(), 0);
+	return;
+    }
+    cb->dispatch(e, &sockid);
+}
+
+bool
+XrlSocket6V0p1Client::send_bind(
+	const char*	dst_xrl_target_name,
+	const string&	creator,
+	const string&	sockid,
+	const IPv6&	local_addr,
+	const uint32_t&	local_port,
+	const BindCB&	cb
+)
+{
+    Xrl x(dst_xrl_target_name, "socket6/0.1/bind");
+    x.args().add("creator", creator);
+    x.args().add("sockid", sockid);
+    x.args().add("local_addr", local_addr);
+    x.args().add("local_port", local_port);
+    return _sender->send(x, callback(this, &XrlSocket6V0p1Client::unmarshall_bind, cb));
+}
+
+
+/* Unmarshall bind */
+void
+XrlSocket6V0p1Client::unmarshall_bind(
+	const XrlError&	e,
+	XrlArgs*	a,
+	BindCB		cb
+)
+{
+    if (e != XrlError::OKAY()) {
+	cb->dispatch(e);
+	return;
+    } else if (a && a->size() != 0) {
+	XLOG_ERROR("Wrong number of arguments (%u != %u)", XORP_UINT_CAST(a->size()), XORP_UINT_CAST(0));
+	cb->dispatch(XrlError::BAD_ARGS());
+	return;
+    }
+    cb->dispatch(e);
+}
+
+bool
 XrlSocket6V0p1Client::send_tcp_open_and_bind(
 	const char*	dst_xrl_target_name,
 	const string&	creator,
Index: xrl/interfaces/socket6.xif
===================================================================
RCS file: /cvs/xorp/xrl/interfaces/socket6.xif,v
retrieving revision 1.4
diff -u -r1.4 socket6.xif
--- xrl/interfaces/socket6.xif	12 Sep 2006 22:56:40 -0000	1.4
+++ xrl/interfaces/socket6.xif	26 Mar 2007 12:14:02 -0000
@@ -20,6 +20,52 @@
 interface socket6/0.1 {
 
     /**
+     * Open a tcp socket.
+     *
+     * @param creator the Xrl Target instance name of the socket
+     *        creator.  The named target must implement socket4_user/0.1.
+     *
+     * @param is_blocking if true then the socket will be blocking, otherwise
+     *        non-blocking.
+     *
+     * @param sockid return parameter that contains unique socket id when
+     *        socket instantiation is successful.
+     */
+    tcp_open			? creator:txt				\
+				& is_blocking:bool			\
+				-> sockid:txt
+
+    /**
+     * Open a udp socket.
+     *
+     * @param creator the Xrl Target instance name of the socket
+     *        creator.  The named target must implement socket4_user/0.1.
+     *
+     * @param is_blocking if true then the socket will be blocking, otherwise
+     *        non-blocking.
+     *
+     * @param sockid return parameter that contains unique socket id when
+     *        socket instantiation is successful.
+     */
+    udp_open			? creator:txt				\
+				& is_blocking:bool			\
+				-> sockid:txt
+
+    /**
+     * Bind a socket.
+     *
+     * @param sockid the socket id of the socket to bind.
+     *
+     * @param local_addr the interface address to bind socket to.
+     *
+     * @param local_port the port to bind socket to.
+     */
+    bind			? creator:txt				\
+				& sockid:txt                            \
+				& local_addr:ipv6                       \
+				& local_port:u32
+
+    /**
      * Create a bound TCP socket.
      *
      * @param creator the Xrl Target instance name of the socket
@@ -63,7 +109,6 @@
 				& is_blocking:bool			\
 				-> sockid:txt
 
-
     /**
      * Create a bound UDP multicast socket.
      *
@@ -95,7 +140,6 @@
 				& is_blocking:bool			\
 				-> sockid:txt
 
-
     /**
      * Create a bound and connected TCP socket.
      *
@@ -152,7 +196,6 @@
 				& is_blocking:bool			\
 				-> sockid:txt
 
-
     /**
      * Join multicast group on already bound socket.
      *
@@ -181,7 +224,6 @@
 				& mcast_addr:ipv6			\
 				& leave_if_addr:ipv6
 
-
     /**
      * Close socket.
      *
@@ -201,7 +243,6 @@
     tcp_listen			? sockid:txt				\
 				& backlog:u32
 
-
     /**
      * Send data on socket.
      *
@@ -237,7 +278,6 @@
 				& end_of_record:bool			\
 				& end_of_file:bool
 
-
     /**
      * Send data on socket to a given destination.  The packet is not
      * routed as the forwarding engine sending the packet may not have
@@ -301,7 +341,6 @@
 				& ifaddr:ipv6				\
 				& data:binary
 
-
     /**
      * Set a named socket option.
      *
Index: xrl/interfaces/socket4.xif
===================================================================
RCS file: /cvs/xorp/xrl/interfaces/socket4.xif,v
retrieving revision 1.5
diff -u -r1.5 socket4.xif
--- xrl/interfaces/socket4.xif	12 Sep 2006 22:56:40 -0000	1.5
+++ xrl/interfaces/socket4.xif	26 Mar 2007 12:14:01 -0000
@@ -20,6 +20,52 @@
 interface socket4/0.1 {
 
     /**
+     * Open a tcp socket.
+     *
+     * @param creator the Xrl Target instance name of the socket
+     *        creator.  The named target must implement socket4_user/0.1.
+     *
+     * @param is_blocking if true then the socket will be blocking, otherwise
+     *        non-blocking.
+     *
+     * @param sockid return parameter that contains unique socket id when
+     *        socket instantiation is successful.
+     */
+    tcp_open			? creator:txt				\
+				& is_blocking:bool			\
+				-> sockid:txt
+
+    /**
+     * Open a udp socket.
+     *
+     * @param creator the Xrl Target instance name of the socket
+     *        creator.  The named target must implement socket4_user/0.1.
+     *
+     * @param is_blocking if true then the socket will be blocking, otherwise
+     *        non-blocking.
+     *
+     * @param sockid return parameter that contains unique socket id when
+     *        socket instantiation is successful.
+     */
+    udp_open			? creator:txt				\
+				& is_blocking:bool			\
+				-> sockid:txt
+
+    /**
+     * Bind a socket.
+     *
+     * @param sockid the socket id of the socket to bind.
+     *
+     * @param local_addr the interface address to bind socket to.
+     *
+     * @param local_port the port to bind socket to.
+     */
+    bind			? creator:txt				\
+				& sockid:txt				\
+				& local_addr:ipv4			\
+				& local_port:u32
+
+    /**
      * Create a bound TCP socket.
      *
      * @param creator the Xrl Target instance name of the socket
@@ -63,7 +109,6 @@
 				& is_blocking:bool			\
 				-> sockid:txt
 
-
     /**
      * Create a bound UDP multicast socket.
      *
@@ -95,7 +140,6 @@
 				& is_blocking:bool			\
 				-> sockid:txt
 
-
     /**
      * Create a bound and connected TCP socket.
      *
@@ -152,7 +196,6 @@
 				& is_blocking:bool			\
 				-> sockid:txt
 
-
     /**
      * Join multicast group on already bound socket.
      *
@@ -181,7 +224,6 @@
 				& mcast_addr:ipv4			\
 				& leave_if_addr:ipv4
 
-
     /**
      * Close socket.
      *
@@ -201,7 +243,6 @@
     tcp_listen			? sockid:txt				\
 				& backlog:u32
 
-
     /**
      * Send data on socket.
      *
@@ -237,7 +278,6 @@
 				& end_of_record:bool			\
 				& end_of_file:bool
 
-
     /**
      * Send data on socket to a given destination.  The packet is not
      * routed as the forwarding engine sending the packet may not have
@@ -301,7 +341,6 @@
 				& ifaddr:ipv4				\
 				& data:binary
 
-
     /**
      * Set a named socket option.
      *
Index: xrl/interfaces/socket4_xif.hh
===================================================================
RCS file: /cvs/xorp/xrl/interfaces/socket4_xif.hh,v
retrieving revision 1.11
diff -u -r1.11 socket4_xif.hh
--- xrl/interfaces/socket4_xif.hh	16 Feb 2007 22:47:44 -0000	1.11
+++ xrl/interfaces/socket4_xif.hh	26 Mar 2007 12:14:02 -0000
@@ -28,24 +28,37 @@
     XrlSocket4V0p1Client(XrlSender* s) : _sender(s) {}
     virtual ~XrlSocket4V0p1Client() {}
 
+    typedef XorpCallback2<void, const XrlError&, const string*>::RefPtr TcpOpenCB;
+
+    bool send_tcp_open(
+	const char*	dst_xrl_target_name,
+	const string&	creator,
+	const bool&	is_blocking,
+	const TcpOpenCB&	cb
+    );
+
+    typedef XorpCallback2<void, const XrlError&, const string*>::RefPtr UdpOpenCB;
+
+    bool send_udp_open(
+	const char*	dst_xrl_target_name,
+	const string&	creator,
+	const bool&	is_blocking,
+	const UdpOpenCB&	cb
+    );
+
+    typedef XorpCallback1<void, const XrlError&>::RefPtr BindCB;
+
+    bool send_bind(
+	const char*	dst_xrl_target_name,
+	const string&	creator,
+	const string&	sockid,
+	const IPv4&	local_addr,
+	const uint32_t&	local_port,
+	const BindCB&	cb
+    );
+
     typedef XorpCallback2<void, const XrlError&, const string*>::RefPtr TcpOpenAndBindCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Create a bound TCP socket.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param creator the Xrl Target instance name of the socket creator. The
-     *  named target must implement socket4_user/0.1.
-     *
-     *  @param local_addr the interface address to bind socket to.
-     *
-     *  @param local_port the port to bind socket to.
-     *
-     *  @param is_blocking if true then the socket will be blocking, otherwise
-     *  non-blocking.
-     */
+
     bool send_tcp_open_and_bind(
 	const char*	dst_xrl_target_name,
 	const string&	creator,
@@ -56,23 +69,7 @@
     );
 
     typedef XorpCallback2<void, const XrlError&, const string*>::RefPtr UdpOpenAndBindCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Create a bound UDP socket.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param creator the Xrl Target instance name of the socket creator. The
-     *  named target must implement socket4_user/0.1.
-     *
-     *  @param local_addr the interface address to bind socket to.
-     *
-     *  @param local_port the port to bind socket to.
-     *
-     *  @param is_blocking if true then the socket will be blocking, otherwise
-     *  non-blocking.
-     */
+
     bool send_udp_open_and_bind(
 	const char*	dst_xrl_target_name,
 	const string&	creator,
@@ -83,29 +80,7 @@
     );
 
     typedef XorpCallback2<void, const XrlError&, const string*>::RefPtr UdpOpenBindJoinCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Create a bound UDP multicast socket.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param creator the Xrl Target instance name of the socket creator. The
-     *  named target must implement socket4_user/0.1.
-     *
-     *  @param local_addr the interface address to bind socket to.
-     *
-     *  @param local_port the port to bind socket to.
-     *
-     *  @param mcast_addr the multicast group address to join.
-     *
-     *  @param ttl the ttl to use for this multicast socket.
-     *
-     *  @param reuse allow other sockets to bind to same multicast group.
-     *
-     *  @param is_blocking if true then the socket will be blocking, otherwise
-     *  non-blocking.
-     */
+
     bool send_udp_open_bind_join(
 	const char*	dst_xrl_target_name,
 	const string&	creator,
@@ -119,27 +94,7 @@
     );
 
     typedef XorpCallback2<void, const XrlError&, const string*>::RefPtr TcpOpenBindConnectCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Create a bound and connected TCP socket.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param creator the Xrl Target instance name of the socket creator. The
-     *  named target must implement socket4_user/0.1.
-     *
-     *  @param local_addr the interface address to bind socket to.
-     *
-     *  @param local_port the port to bind socket to.
-     *
-     *  @param remote_addr the address to connect to.
-     *
-     *  @param remote_port the remote port to connect to.
-     *
-     *  @param is_blocking if true then the socket will be blocking, otherwise
-     *  non-blocking.
-     */
+
     bool send_tcp_open_bind_connect(
 	const char*	dst_xrl_target_name,
 	const string&	creator,
@@ -152,27 +107,7 @@
     );
 
     typedef XorpCallback2<void, const XrlError&, const string*>::RefPtr UdpOpenBindConnectCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Create a bound and connected UDP socket.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param creator the Xrl Target instance name of the socket creator. The
-     *  named target must implement socket4_user/0.1.
-     *
-     *  @param local_addr the interface address to bind socket to.
-     *
-     *  @param local_port the port to bind socket to.
-     *
-     *  @param remote_addr the address to connect to.
-     *
-     *  @param remote_port the remote port to connect to.
-     *
-     *  @param is_blocking if true then the socket will be blocking, otherwise
-     *  non-blocking.
-     */
+
     bool send_udp_open_bind_connect(
 	const char*	dst_xrl_target_name,
 	const string&	creator,
@@ -185,19 +120,7 @@
     );
 
     typedef XorpCallback1<void, const XrlError&>::RefPtr UdpJoinGroupCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Join multicast group on already bound socket.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param sockid unique socket id.
-     *
-     *  @param mcast_addr group to join.
-     *
-     *  @param join_if_addr interface address to perform join on.
-     */
+
     bool send_udp_join_group(
 	const char*	dst_xrl_target_name,
 	const string&	sockid,
@@ -207,19 +130,7 @@
     );
 
     typedef XorpCallback1<void, const XrlError&>::RefPtr UdpLeaveGroupCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Leave multicast group on already bound socket.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param sockid unique socket id.
-     *
-     *  @param mcast_addr group to leave.
-     *
-     *  @param leave_if_addr interface address to perform leave on.
-     */
+
     bool send_udp_leave_group(
 	const char*	dst_xrl_target_name,
 	const string&	sockid,
@@ -229,15 +140,7 @@
     );
 
     typedef XorpCallback1<void, const XrlError&>::RefPtr CloseCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Close socket.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param sockid unique socket id of socket to be closed.
-     */
+
     bool send_close(
 	const char*	dst_xrl_target_name,
 	const string&	sockid,
@@ -245,19 +148,7 @@
     );
 
     typedef XorpCallback1<void, const XrlError&>::RefPtr TcpListenCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Listen for inbound connections on socket. When a connection request
-     *  received the socket creator will receive notification through
-     *  socket4_user/0.1/connect_event.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param sockid the unique socket id of the socket to perform listen.
-     *
-     *  @param backlog the maximum number of pending connections.
-     */
+
     bool send_tcp_listen(
 	const char*	dst_xrl_target_name,
 	const string&	sockid,
@@ -266,17 +157,7 @@
     );
 
     typedef XorpCallback1<void, const XrlError&>::RefPtr SendCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Send data on socket.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param sockid unique socket id.
-     *
-     *  @param data block of data to be sent.
-     */
+
     bool send_send(
 	const char*	dst_xrl_target_name,
 	const string&	sockid,
@@ -285,27 +166,7 @@
     );
 
     typedef XorpCallback1<void, const XrlError&>::RefPtr SendWithFlagsCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Send data on socket with optional flags. These flags provide hints to
-     *  the forwarding engine on how to send the packets, they are not
-     *  guaranteed to work. NB: There is no flag for "do not route" as this is
-     *  always true since the particular forwarding engine sending the data may
-     *  not have access to the full routing table.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param sockid unique socket id.
-     *
-     *  @param data block of data to be sent.
-     *
-     *  @param out_of_band mark data as out of band.
-     *
-     *  @param end_of_record data completes record.
-     *
-     *  @param end_of_file data completes file.
-     */
+
     bool send_send_with_flags(
 	const char*	dst_xrl_target_name,
 	const string&	sockid,
@@ -317,23 +178,7 @@
     );
 
     typedef XorpCallback1<void, const XrlError&>::RefPtr SendToCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Send data on socket to a given destination. The packet is not routed as
-     *  the forwarding engine sending the packet may not have access to the
-     *  full routing table.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param sockid unique socket id.
-     *
-     *  @param remote_addr destination address for data.
-     *
-     *  @param remote_port destination port for data.
-     *
-     *  @param data block of data to be sent.
-     */
+
     bool send_send_to(
 	const char*	dst_xrl_target_name,
 	const string&	sockid,
@@ -344,29 +189,7 @@
     );
 
     typedef XorpCallback1<void, const XrlError&>::RefPtr SendToWithFlagsCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Send data on socket to a given destination. The packet is not routed as
-     *  the forwarding engine sending the packet may not have access to the
-     *  full routing table.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param sockid unique socket id.
-     *
-     *  @param remote_addr destination address for data.
-     *
-     *  @param remote_port destination port for data.
-     *
-     *  @param data block of data to be sent.
-     *
-     *  @param out_of_band mark data as out of band.
-     *
-     *  @param end_of_record data completes record.
-     *
-     *  @param end_of_file data completes file.
-     */
+
     bool send_send_to_with_flags(
 	const char*	dst_xrl_target_name,
 	const string&	sockid,
@@ -380,21 +203,7 @@
     );
 
     typedef XorpCallback1<void, const XrlError&>::RefPtr SendFromMulticastIfCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Send data on socket to a given multicast group from a given interface.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param sockid unique socket id.
-     *
-     *  @param group_addr destination address for data.
-     *
-     *  @param group_port destination port for data.
-     *
-     *  @param ifaddr interface address
-     */
+
     bool send_send_from_multicast_if(
 	const char*	dst_xrl_target_name,
 	const string&	sockid,
@@ -406,21 +215,7 @@
     );
 
     typedef XorpCallback1<void, const XrlError&>::RefPtr SetSocketOptionCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Set a named socket option.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param sockid unique socket id.
-     *
-     *  @param optname name of option to be set. Valid values are:
-     *  "multicast_loopback" "multicast_ttl"
-     *
-     *  @param optval value of option to be set. If value is logically boolean
-     *  then zero represents false and any non-zero value true.
-     */
+
     bool send_set_socket_option(
 	const char*	dst_xrl_target_name,
 	const string&	sockid,
@@ -430,18 +225,7 @@
     );
 
     typedef XorpCallback2<void, const XrlError&, const uint32_t*>::RefPtr GetSocketOptionCB;
-    /**
-     *  Send Xrl intended to:
-     *
-     *  Get a named socket option.
-     *
-     *  @param dst_xrl_target_name the Xrl target name of the destination.
-     *
-     *  @param sockid unique socket id.
-     *
-     *  @param optname name of option to be set. Valid values are documented in
-     *  set_socket_option.
-     */
+
     bool send_get_socket_option(
 	const char*	dst_xrl_target_name,
 	const string&	sockid,
@@ -453,6 +237,24 @@
     XrlSender* _sender;
 
 private:
+    void unmarshall_tcp_open(
+	const XrlError&	e,
+	XrlArgs*	a,
+	TcpOpenCB		cb
+    );
+
+    void unmarshall_udp_open(
+	const XrlError&	e,
+	XrlArgs*	a,
+	UdpOpenCB		cb
+    );
+
+    void unmarshall_bind(
+	const XrlError&	e,
+	XrlArgs*	a,
+	BindCB		cb
+    );
+
     void unmarshall_tcp_open_and_bind(
 	const XrlError&	e,
 	XrlArgs*	a,
Index: cli/cli_node_net.cc
===================================================================
RCS file: /cvs/xorp/cli/cli_node_net.cc,v
retrieving revision 1.56
diff -u -r1.56 cli_node_net.cc
--- cli/cli_node_net.cc	16 Feb 2007 22:45:29 -0000	1.56
+++ cli/cli_node_net.cc	26 Mar 2007 12:13:58 -0000
@@ -129,7 +129,10 @@
 	_cli_socket.clear();
 	break;
     }
-    
+    if (comm_listen(_cli_socket, COMM_DEFAULT_BACKLOG) != XORP_OK) {
+	_cli_socket.clear();
+	return XORP_ERROR;
+    }
     return (_cli_socket);
 }
 
Index: bgp/socket.cc
===================================================================
RCS file: /cvs/xorp/bgp/socket.cc,v
retrieving revision 1.46
diff -u -r1.46 socket.cc
--- bgp/socket.cc	16 Feb 2007 22:45:19 -0000	1.46
+++ bgp/socket.cc	26 Mar 2007 12:13:57 -0000
@@ -64,6 +64,9 @@
     if (!_s.is_valid()) {
 	XLOG_ERROR("comm_bind_tcp failed");
     }
+    if (comm_listen(_s, 5) != XORP_OK) {
+	XLOG_ERROR("comm_listen failed");
+    }
 }
 
 /* **************** BGPSocket - PROTECTED METHODS *********************** */
Index: bgp/peer.hh
===================================================================
RCS file: /cvs/xorp/bgp/peer.hh,v
retrieving revision 1.43
diff -u -r1.43 peer.hh
--- bgp/peer.hh	16 Feb 2007 22:45:14 -0000	1.43
+++ bgp/peer.hh	26 Mar 2007 12:13:57 -0000
@@ -359,7 +359,7 @@
  *
  * Under normal circumstances only one connection attempt will be
  * taking place. When both BGP processes at either end of a session
- * attempt to make a conection at the same time there may be a
+ * attempt to make a connection at the same time there may be a
  * connection collision in this case it is necessary to hold two TCP
  * connections until an open message is seen by the peer to decide
  * which session should be selected. If a connection collision is
Index: libxipc/finder_tcp.cc
===================================================================
RCS file: /cvs/xorp/libxipc/finder_tcp.cc,v
retrieving revision 1.30
diff -u -r1.30 finder_tcp.cc
--- libxipc/finder_tcp.cc	16 Feb 2007 22:46:06 -0000	1.30
+++ libxipc/finder_tcp.cc	26 Mar 2007 12:14:01 -0000
@@ -296,6 +296,9 @@
     if (!_lsock.is_valid()) {
 	xorp_throw(InvalidPort, comm_get_last_error_str());
     }
+    if (comm_listen(_lsock, COMM_DEFAULT_BACKLOG) != XORP_OK) {
+	xorp_throw(InvalidPort, comm_get_last_error_str());
+    }
 
     if (en)
 	set_enabled(en);
Index: libxipc/xrl_pf_stcp.cc
===================================================================
RCS file: /cvs/xorp/libxipc/xrl_pf_stcp.cc,v
retrieving revision 1.53
diff -u -r1.53 xrl_pf_stcp.cc
--- libxipc/xrl_pf_stcp.cc	16 Feb 2007 22:46:12 -0000	1.53
+++ libxipc/xrl_pf_stcp.cc	26 Mar 2007 12:14:01 -0000
@@ -363,6 +363,10 @@
 	xorp_throw(XrlPFConstructorError,
 		   comm_get_last_error_str());
     }
+    if (comm_listen(_sock, COMM_DEFAULT_BACKLOG) != XORP_OK) {
+	xorp_throw(XrlPFConstructorError,
+		   comm_get_last_error_str());
+    }
 
     string addr;
     if (get_local_socket_details(_sock, addr, port) == false) {
Index: fea/test_xrl_sockets4_tcp.cc
===================================================================
RCS file: fea/test_xrl_sockets4_tcp.cc
diff -N fea/test_xrl_sockets4_tcp.cc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ fea/test_xrl_sockets4_tcp.cc	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,1448 @@
+// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
+
+// Copyright (c) 2001-2006 International Computer Science Institute
+//
+// 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, subject to the conditions
+// listed in the XORP LICENSE file. These conditions include: you must
+// preserve this copyright notice, and you cannot mention the copyright
+// holders in advertising related to the Software without their permission.
+// The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
+// notice is a summary of the XORP LICENSE file; the license in that file is
+// legally binding.
+
+#include "fea_module.h"
+
+#include "libxorp/xorp.h"
+#include "libxorp/xlog.h"
+#include "libxorp/debug.h"
+#include "libxorp/status_codes.h"
+#include "libxorp/xorpfd.hh"
+
+#include <set>
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include "libxipc/sockutil.hh"
+#include "libxipc/xrl_std_router.hh"
+
+#include "xrl/interfaces/socket4_xif.hh"
+#include "xrl/targets/test_socket4_base.hh"
+
+#include "xrl_socket_server.hh"
+#include "addr_table.hh"
+
+
+static const uint8_t FILLER_VALUE = 0xe7;
+
+// ---------------------------------------------------------------------------
+// Verbose output control
+
+static bool s_verbose = false;
+
+inline bool verbose()           { return s_verbose; }
+inline void set_verbose(bool v) { s_verbose = v; }
+
+#define verbose_log(x...)                                                     \
+do {                                                                          \
+    if (verbose()) {                                                          \
+        printf("From %s:%d: ", __FILE__, __LINE__);                           \
+        printf(x);                                                            \
+	fflush(stdout);							      \
+    }                                                                         \
+} while(0)
+
+#define verbose_err(x...)                                                     \
+do {                                                                          \
+    printf("From %s:%d: ", __FILE__, __LINE__);                               \
+    printf(x);                                                                \
+    fflush(stdout);							      \
+} while(0)
+
+
+// ----------------------------------------------------------------------------
+// TestAddressTable definition and implementation
+
+class TestAddressTable : public AddressTableBase {
+public:
+    void add_address(const IPv4& addr);
+    void remove_address(const IPv4& addr);
+    bool address_valid(const IPv6& addr) const;
+
+    void add_address(const IPv6& addr);
+    void remove_address(const IPv6& addr);
+    bool address_valid(const IPv4& addr) const;
+
+    uint32_t address_pif_index(const IPv4&) const { return 0; }
+    uint32_t address_pif_index(const IPv6&) const { return 0; }
+
+protected:
+    set<IPv4> _v4s;
+    set<IPv6> _v6s;
+};
+
+void
+TestAddressTable::add_address(const IPv4& a)
+{
+    _v4s.insert(a);
+}
+
+void
+TestAddressTable::remove_address(const IPv4& a)
+{
+    set<IPv4>::iterator i = _v4s.find(a);
+    if (i != _v4s.end()) {
+	_v4s.erase(i);
+	invalidate_address(a, "invalidated");
+    }
+}
+
+bool
+TestAddressTable::address_valid(const IPv4& a) const
+{
+    return _v4s.find(a) != _v4s.end();
+}
+
+void
+TestAddressTable::add_address(const IPv6& a)
+{
+    _v6s.insert(a);
+}
+
+void
+TestAddressTable::remove_address(const IPv6& a)
+{
+    set<IPv6>::iterator i = _v6s.find(a);
+    if (i != _v6s.end()) {
+	_v6s.erase(i);
+	invalidate_address(a, "invalidated");
+    }
+}
+
+bool
+TestAddressTable::address_valid(const IPv6& a) const
+{
+    return _v6s.find(a) != _v6s.end();
+}
+
+//
+// ----------------------------------------------------------------------------
+// Scheduling Time class
+class SchedulingTime {
+private:
+	int _time;
+	int _increment;
+	
+public:
+	SchedulingTime(int start_time =0, int increment =250) 
+	: _time(start_time), _increment(increment) {}
+	
+	inline int now() { return _time; } 
+	inline int next() { _time += _increment; return _time; }
+	inline int next(int inc) { _time += inc; return _time; }
+};
+
+//
+// ----------------------------------------------------------------------------
+// TCP client/server commonalities class
+
+class TestSocket4TCP : public XrlTestSocket4TargetBase {
+public:
+    TestSocket4TCP(EventLoop& e, const string& ssname,
+		   IPv4 finder_host, uint16_t finder_port) :
+		   _e(e), _ssname(ssname), _p_snd(0), _p_rcv(0),
+		   _b_snd(0), _b_rcv(0), _x_err(0) {
+	_r = new XrlStdRouter(_e, "test_xrl_socket", finder_host, finder_port);
+	set_command_map(_r);
+	_r->finalize();
+    }
+
+    ~TestSocket4TCP()
+    {
+	set_command_map(0);
+	delete _r;
+	_r = 0;
+    }
+
+    inline uint32_t bytes_received() const	{ return _b_rcv; }
+    inline uint32_t bytes_sent() const		{ return _b_snd; }
+    inline uint32_t packets_received() const	{ return _p_rcv; }
+    inline uint32_t packets_sent() const	{ return _p_snd; }
+    inline uint32_t xrl_errors() const		{ return _x_err; }
+
+    /**
+     * Stop sending packets.
+     */
+    void
+    stop_sending()
+    {
+	_t_snd.unschedule();
+    }
+
+    /**
+     * Send the specified number of bytes of data through the given socket.
+     *
+     * On success, the number of sent bytes and packets is bumped up
+     * accordingly, and true is returned. On failure the number of xrl
+     * errors is bumped by one, and the sending timer stopped.
+     */
+    bool
+    send_data(string& sockid, uint32_t bytes)
+    {
+	vector<uint8_t> data(bytes, FILLER_VALUE);
+	XrlSocket4V0p1Client c(_r);
+	if (c.send_send(_ssname.c_str(), sockid, data,
+		callback(this, &TestSocket4TCP::send_data_cb))) {
+	    verbose_log("Sent %u bytes...\n", bytes);
+	    _b_snd += bytes;
+	    _p_snd += 1;
+	    return true;
+	}
+	return false;
+    }
+
+
+protected:
+    virtual bool send_data(uint32_t bytes) = 0;
+    virtual void send_data_cb(const XrlError& e) = 0;
+public:
+    virtual void start_sending(uint32_t bytes, uint32_t ipg_ms) = 0;
+
+protected:
+    XrlCmdError
+    common_0_1_get_target_name(string& name)
+    {
+	name = _r->instance_name();
+	return XrlCmdError::OKAY();
+    }
+
+    XrlCmdError
+    common_0_1_get_version(string& version)
+    {
+	version = "0.1";
+	return XrlCmdError::OKAY();
+    }
+
+    XrlCmdError
+    common_0_1_get_status(uint32_t& status, string& reason)
+    {
+	status = PROC_READY;
+	reason = "";
+	return XrlCmdError::OKAY();
+    }
+
+    XrlCmdError
+    common_0_1_shutdown()
+    {
+	return XrlCmdError::COMMAND_FAILED("Not supported");
+    }
+
+    XrlCmdError
+    socket4_user_0_1_recv_event(const string&		sockid,
+				const IPv4&		src_host,
+				const uint32_t&		src_port,
+				const vector<uint8_t>&	data) = 0;
+
+    XrlCmdError
+    socket4_user_0_1_connect_event(const string& 	sockid,
+				   const IPv4&		src_host,
+				   const uint32_t&	src_port,
+				   const string&	new_sockid,
+				   bool&		accept) = 0;
+
+    XrlCmdError
+    socket4_user_0_1_error_event(const string& 		sockid, 
+				 const string&		error,
+				 const bool&		fatal) = 0;
+
+    XrlCmdError
+    socket4_user_0_1_close_event(const string&	sockid,
+				 const string&	reason) = 0;
+
+    EventLoop&	_e;
+    XrlRouter*	_r;
+    string	_ssname;
+
+    uint32_t	_p_snd;		// packets sent
+    uint32_t	_p_rcv;		// packets received
+    uint32_t	_b_snd;		// bytes sent
+    uint32_t	_b_rcv;		// bytes received
+    uint32_t	_x_err;		// xrl error count
+
+    XorpTimer	_t_snd;		// send timer
+};
+
+//
+// ----------------------------------------------------------------------------
+// TCP Server
+
+class TestSocket4TCPServer : public TestSocket4TCP {
+
+public:
+    TestSocket4TCPServer(EventLoop& e, const string& ssname,
+		   IPv4 finder_host, uint16_t finder_port)
+	: TestSocket4TCP(e, ssname, finder_host, finder_port),
+	  _server_closed(true), _client_closed(true) {}
+
+    inline bool	server_closed() const { return _server_closed; }
+    inline bool	client_closed() const { return _client_closed; }
+
+    /**
+     * Bind to interface and port.
+     *
+     * This is an asynchronous request.  If the request is
+     * successfully queued for dispatch then true is returned.
+     *
+     * Subsequently, if the request is successful _server_sockid is set to a
+     * valid socket identifier, and _server_closed set to false.
+     * If unsuccessful the number of xrl errors is bumped by one.
+     */
+    bool
+    bind(IPv4 addr, uint16_t port)
+    {
+	XrlSocket4V0p1Client c(_r);
+	verbose_log("Sending bind (%s:%u) request.\n",
+		    addr.str().c_str(), port);
+	return c.send_tcp_open_and_bind(
+	    _ssname.c_str(), _r->instance_name(), addr, port, false,
+	    callback(this, &TestSocket4TCPServer::bind_cb));
+    }
+
+    /**
+     * Listen on the server socket.
+     *
+     * This is an asynchronous request.  If the request is
+     * successfully queued for dispatch then true is returned.
+     */
+    bool
+    listen(uint32_t backlog)
+    {
+	XrlSocket4V0p1Client c(_r);
+	verbose_log("Sending listen request.\n");
+	bool s = c.send_tcp_listen(
+	    _ssname.c_str(), _server_sockid, backlog,
+	    callback(this, &TestSocket4TCPServer::listen_cb));
+	return s;
+    }
+
+    /**
+     * Request closure of the server socket.
+     *
+     * This is an asychronous request.  If the request is successfully
+     * queued for dispatch then true is returned.
+     *
+     * On success _server_sockid is cleared.  On failure the number xrl
+     * errors is bumped by one.
+     */
+    bool
+    close_server()
+    {
+	XrlSocket4V0p1Client c(_r);
+	verbose_log("Sending close request for server socket.\n");
+	return c.send_close(_ssname.c_str(), _server_sockid,
+	      callback(this, &TestSocket4TCPServer::close_server_cb));
+    }
+
+    /**
+     * Request closure of the client socket (request a disconnect
+     * of the client).
+     *
+     * This is an asychronous request.  If the request is successfully
+     * queued for dispatch then true is returned.
+     *
+     * On success _client_sockid is cleared.  On failure the number xrl
+     * errors is bumped by one.
+     */
+    bool
+    close_client()
+    {
+	XrlSocket4V0p1Client c(_r);
+	verbose_log("Sending close request for server client socket.\n");
+	return c.send_close(_ssname.c_str(), _client_sockid,
+	      callback(this, &TestSocket4TCPServer::close_client_cb));
+    }
+
+    /**
+     * Send data to the connected client, through the client socket.
+     *
+     * For implementation, see TestSocket4TCP::send_data.
+     */
+    bool
+    send_data(uint32_t bytes)
+    {
+	return TestSocket4TCP::send_data(_client_sockid, bytes);
+    }
+
+    /**
+     * Start sending packets.
+     *
+     * @param bytes size of each packet.
+     * @param ipg_ms interpacket gap in milliseconds.
+     */
+    void
+    start_sending(uint32_t bytes, uint32_t ipg_ms)
+    {
+	_t_snd = _e.new_periodic_ms(ipg_ms,
+	    callback(this, &TestSocket4TCPServer::send_data, bytes));
+    }
+
+protected:
+
+    //
+    // Callback functions
+    //
+
+    void
+    bind_cb(const XrlError& e, const string* psockid)
+    {
+	if (e != XrlError::OKAY()) {
+	    verbose_err("Xrl Error: %s\n", e.str().c_str());
+	    _x_err ++;
+	    return;
+	}
+	_server_sockid = *psockid;
+	_server_closed = false;
+    }
+
+    void
+    listen_cb(const XrlError& e)
+    {
+	if (e != XrlError::OKAY()) {
+	    verbose_err("Xrl Error: %s\n", e.str().c_str());
+	    _x_err ++;
+	    return;
+	}
+    }
+
+    void
+    close_server_cb(const XrlError& e)
+    {
+	if (e != XrlError::OKAY()) {
+	    verbose_err("Xrl Error: %s\n", e.str().c_str());
+	    _x_err ++;
+	}
+	_server_sockid.erase();
+	_server_closed = true;
+    }
+
+    void
+    close_client_cb(const XrlError& e)
+    {
+	if (e != XrlError::OKAY()) {
+	    verbose_err("Xrl Error: %s\n", e.str().c_str());
+	    _x_err ++;
+	}
+	_client_sockid.erase();
+	_client_closed = true;
+    }
+
+    void
+    send_data_cb(const XrlError& e)
+    {
+	if (e != XrlError::OKAY()) {
+	    verbose_err("Xrl Error: %s\n", e.str().c_str());
+	    stop_sending();
+	    _x_err ++;
+	}
+    }
+
+    //
+    // Socket User Interface functions
+    //
+
+    XrlCmdError
+    socket4_user_0_1_recv_event(const string&	sockid,
+				const IPv4&	src_host,
+				const uint32_t&	src_port,
+				const vector<uint8_t>&	data)
+    {
+	/* should only be receiving data on the client socket */
+	XLOG_ASSERT(_client_sockid == sockid);
+	verbose_log("Server received %d bytes from %s:%u\n",
+		    data.size(), src_host.str().c_str(), src_port);
+	_p_rcv += 1;
+	for (size_t i = 0; i < data.size(); i++) {
+	    if (data[i] != FILLER_VALUE) {
+		return XrlCmdError::COMMAND_FAILED("Bad data received.");
+	    }
+	}
+	_b_rcv += data.size();
+	return XrlCmdError::OKAY();
+    }
+
+    XrlCmdError
+    socket4_user_0_1_connect_event(const string& sockid,
+				   const IPv4&		src_host,
+				   const uint32_t&	src_port,
+				   const string&	new_sockid,
+				   bool&			accept)
+    {
+	/* should only be receiving connections from the server socket */
+	XLOG_ASSERT(sockid == _server_sockid);
+	verbose_log("Accepting connection from %s:%d\n",
+    			src_host.str().c_str(), src_port);
+	accept = true; // Here we would decide whether to accept or reject.
+	_client_sockid = new_sockid;
+	_client_closed = false;
+	return XrlCmdError::OKAY();
+    }
+
+    XrlCmdError
+    socket4_user_0_1_error_event(const string&	sockid,
+				 const string&	error,
+				 const bool&	fatal)
+    {
+	/* socket must be one of the two... */
+	XLOG_ASSERT(sockid == _server_sockid || sockid == _client_sockid);
+	verbose_log("Server error event on %s socket: %s (fatal = %d)\n",
+			(sockid == _server_sockid) ? "server" : "client",
+			error.c_str(), fatal);
+	return XrlCmdError::OKAY();
+    }
+
+    XrlCmdError
+    socket4_user_0_1_close_event(const string&	sockid,
+				 const string&	reason)
+    {
+	/* socket must be one of the two... */
+	XLOG_ASSERT(sockid == _server_sockid || sockid == _client_sockid);
+	verbose_log("Server close event on %s socket: %s\n",
+	    (sockid == _server_sockid) ? "server" : "client", reason.c_str());
+	if (sockid == _server_sockid)
+	    _server_closed = true;
+	else
+	    _client_closed = true;
+	return XrlCmdError::OKAY();
+    }
+
+
+
+
+private:
+    string 	_server_sockid;
+    string	_client_sockid;
+    bool 	_server_closed;	/* flag indicating if server socket is closed */
+    bool	_client_closed;	/* flag indicating if client socket is closed */
+};
+
+//
+// ----------------------------------------------------------------------------
+// TCP Client
+
+class TestSocket4TCPClient : public TestSocket4TCP {
+
+public:
+    TestSocket4TCPClient(EventLoop& e, const string& ssname,
+		   IPv4 finder_host, uint16_t finder_port)
+	: TestSocket4TCP(e, ssname, finder_host, finder_port),
+	  _closed(true) {}
+
+    inline bool	closed() const { return _closed; }
+
+    /**
+     * Bind to interface and port, and connect to remote address and port.
+     *
+     * Subsequently, if the request is successful _sockid is set to
+     * a valid socket identifier, and _closed set to false.
+     * If unsuccessful the number of xrl errors is bumped by one.
+     */
+    bool
+    bind_connect(IPv4 local_addr, uint16_t local_port, IPv4 remote_addr,
+		 uint16_t remote_port, bool is_blocking)
+    {
+	XrlSocket4V0p1Client c(_r);
+	verbose_log("Sending bind (%s/%u) and connect request (\"%s\", %s/%u)\n",
+		    local_addr.str().c_str(), local_port,
+		    _ssname.c_str(),
+		    remote_addr.str().c_str(), remote_port);
+	return c.send_tcp_open_bind_connect(
+	    _ssname.c_str(), _r->instance_name(), local_addr, local_port,
+	    remote_addr, remote_port, is_blocking,
+	    callback(this, &TestSocket4TCPClient::bind_connect_cb));
+    }
+
+    /**
+     * Request closure of the client socket.
+     *
+     * On success _sockid is cleared.  On failure the number xrl
+     * errors is bumped by one.
+     */
+    bool
+    close()
+    {
+	XrlSocket4V0p1Client c(_r);
+	verbose_log("Sending close request for client socket.\n");
+	return c.send_close(_ssname.c_str(), _sockid,
+	      callback(this, &TestSocket4TCPClient::close_cb));
+    }
+
+    /**
+     * Send data to the server through the client socket.
+     *
+     * For implementation, see TestSocket4TCP::send_data.
+     */
+    bool
+    send_data(uint32_t bytes)
+    {
+	return TestSocket4TCP::send_data(_sockid, bytes);
+    }
+
+    /**
+     * Start sending packets.
+     *
+     * @param bytes size of each packet.
+     * @param ipg_ms interpacket gap in milliseconds.
+     */
+    void
+    start_sending(uint32_t bytes, uint32_t ipg_ms)
+    {
+	_t_snd = _e.new_periodic_ms(ipg_ms,
+	    callback(this, &TestSocket4TCPClient::send_data, bytes));
+    }
+
+protected:
+
+    //
+    // Callback functions
+    //
+
+    void
+    bind_connect_cb(const XrlError& e, const string* psockid)
+    {
+	if (e != XrlError::OKAY()) {
+	    verbose_err("Xrl Error: %s\n", e.str().c_str());
+	    _x_err ++;
+	    return;
+	}
+	_sockid = *psockid;
+	_closed = false;
+    }
+
+    void
+    close_cb(const XrlError& e)
+    {
+	if (e != XrlError::OKAY()) {
+	    verbose_err("Xrl Error: %s\n", e.str().c_str());
+	    _x_err ++;
+	}
+	_sockid.erase();
+	_closed = true;
+    }
+
+    void
+    send_data_cb(const XrlError& e)
+    {
+	if (e != XrlError::OKAY()) {
+	    verbose_err("Xrl Error: %s\n", e.str().c_str());
+	    stop_sending();
+	    _x_err ++;
+	}
+    }
+
+    //
+    // Socket User Interface functions
+    //
+
+    XrlCmdError
+    socket4_user_0_1_recv_event(const string&	sockid,
+				const IPv4&	src_host,
+				const uint32_t&	src_port,
+				const vector<uint8_t>&	data)
+    {
+	XLOG_ASSERT(_sockid == sockid);
+	verbose_log("Client received %d bytes from %s:%u\n",
+		    data.size(), src_host.str().c_str(), src_port);
+	_p_rcv += 1;
+	for (size_t i = 0; i < data.size(); i++) {
+	    if (data[i] != FILLER_VALUE) {
+		return XrlCmdError::COMMAND_FAILED("Bad data received.");
+	    }
+	}
+	_b_rcv += data.size();
+	return XrlCmdError::OKAY();
+    }
+
+    XrlCmdError
+    socket4_user_0_1_connect_event(const string&    /* sockid */,
+				   const IPv4&	    /* src_host */,
+				   const uint32_t&  /* src_port */,
+				   const string&    /* new_sockid */,
+				   bool&	    /* accept */)
+    {
+	return XrlCmdError::COMMAND_FAILED("Not supported");
+    }
+
+    XrlCmdError
+    socket4_user_0_1_error_event(const string&	sockid,
+				 const string&	error,
+				 const bool&	fatal)
+    {
+	XLOG_ASSERT(sockid == _sockid);
+	verbose_log("Client socket error: %s (fatal = %d)\n",
+		    error.c_str(), fatal);
+	return XrlCmdError::OKAY();
+    }
+
+    XrlCmdError
+    socket4_user_0_1_close_event(const string&	sockid,
+				 const string&	reason)
+    {
+	XLOG_ASSERT(sockid == _sockid);
+	verbose_log("Client close event: %s\n", reason.c_str());
+	_closed = true;
+	return XrlCmdError::OKAY();
+    }	
+
+private:
+    string _sockid; /* socket used to connect to server */
+    bool _closed;   /* flag indicating whether socket is closed */
+};
+
+//
+// ----------------------------------------------------------------------------
+// Main test setup functions
+
+static bool
+ticker()
+{
+    static const char x[] = { '.', 'o', '0', 'O', '0', 'o' };
+    static char erase = '\0';
+    static int p = 0;
+
+    fprintf(stderr, "%c%c", erase, x[p]);
+    p = (p + 1) % (sizeof(x));
+    erase = '\b';
+    return true;
+}
+
+static void
+create_socket_server(EventLoop*		pe,
+		     TestAddressTable*	ptat,
+		     IPv4		addr,
+		     uint16_t		port,
+		     XrlSocketServer**	ppxss)
+{
+    XrlSocketServer* pxss = new XrlSocketServer(*pe, *ptat, addr, port);
+    *ppxss = pxss;
+    verbose_log("Created socket server.\n");
+}
+
+static void
+destroy_socket_server(XrlSocketServer** ppxss)
+{
+    delete *ppxss;
+    *ppxss = 0;
+    verbose_log("Destroyed socket server.\n");
+}
+
+static void
+start_socket_server(XrlSocketServer** ppxss)
+{
+    XrlSocketServer* pxss = *ppxss;
+    pxss->startup();
+    verbose_log("Starting socket server.\n");
+}
+
+static void
+shutdown_socket_server(XrlSocketServer** ppxss)
+{
+    XrlSocketServer* pxss = *ppxss;
+    pxss->shutdown();
+    verbose_log("Shutting down socket server.\n");
+}
+
+static void
+remove_address(TestAddressTable* ta, IPv4 addr)
+{
+    verbose_log("Invalidating address %s\n", addr.str().c_str());
+    ta->remove_address(addr);
+}
+
+static void
+add_address(TestAddressTable* ta, IPv4 addr)
+{
+    verbose_log("Validating address %s\n", addr.str().c_str());
+    ta->add_address(addr);
+}
+
+//
+// ----------------------------------------------------------------------------
+// Main test functions
+
+static void
+verify_socket_owner_count(XrlSocketServer** ppxss, int n, bool* eflag)
+{
+    XrlSocketServer* pxss = *ppxss;
+    int m = pxss->socket_owner_count();
+    if (m != n) {
+	verbose_err("Socket owner count (%d) does not match expected (%d)\n",
+		    m, n);
+	*eflag = true;
+    }
+}
+
+static void
+verify_socket4_count(XrlSocketServer** ppxss, int n, bool* eflag)
+{
+    XrlSocketServer* pxss = *ppxss;
+    int m =  pxss->ipv4_socket_count();
+    if (m != n) {
+	verbose_err("Socket4 count (%d) does not match expected (%d)\n", m, n);
+	*eflag = true;
+    }
+}
+
+//
+// ----------------------------------------------------------------------------
+// Server functions
+
+static void
+create_server(EventLoop*		pe,
+		   XrlSocketServer**	ppxss,
+		   IPv4			finder_host,
+		   uint16_t		finder_port,
+		   TestSocket4TCP**	ppu)
+{
+    XrlSocketServer* pxss = *ppxss;
+    verbose_log("Creating TestSocket4TCPServer instance.\n");
+    *ppu = new TestSocket4TCPServer(*pe, pxss->instance_name(),
+				    finder_host, finder_port);
+}
+
+static void
+bind_server(TestSocket4TCP** ppu, IPv4 addr, uint16_t port, bool *err)
+{
+    TestSocket4TCPServer* pu = dynamic_cast<TestSocket4TCPServer*>(*ppu);
+    bool s = pu->bind(addr, port);
+    if (s == false)
+	*err = true;
+}
+
+static void
+listen_server(TestSocket4TCP** ppu, uint16_t backlog, bool *err)
+{
+    TestSocket4TCPServer* pu = dynamic_cast<TestSocket4TCPServer*>(*ppu);
+    bool s = pu->listen(backlog);
+    if (s == false)
+	*err = true;
+}
+
+static void
+close_server_socket(TestSocket4TCP** ppu)
+{
+    verbose_log("Closing server socket.\n");
+    TestSocket4TCPServer* pu = dynamic_cast<TestSocket4TCPServer*>(*ppu);
+    if (pu->close_server() == false) {
+	verbose_err("Failed to send close server socket request.\n");
+    }
+}
+
+static void
+verify_server_closed(TestSocket4TCP** ppu, bool closed, bool* eflag)
+{
+    TestSocket4TCPServer* pu = dynamic_cast<TestSocket4TCPServer*>(*ppu);
+    if (pu->server_closed() != closed) {
+	verbose_err("Server socket close state (%s) "
+		    "does not matched expected (%s)\n",
+		    pu->server_closed() ? "true" : "false",
+		    closed ? "true" : "false");
+	*eflag = true;
+    }
+}
+
+static void
+close_server_client_socket(TestSocket4TCP** ppu)
+{
+    verbose_log("Closing server client socket.\n");
+    TestSocket4TCPServer* pu = dynamic_cast<TestSocket4TCPServer*>(*ppu);
+    if (pu->close_client() == false) {
+	verbose_err("Failed to send server close client socket request.\n");
+    }
+}
+
+static void
+verify_server_client_closed(TestSocket4TCP** ppu, bool closed, bool* eflag)
+{
+    TestSocket4TCPServer* pu = dynamic_cast<TestSocket4TCPServer*>(*ppu);
+    if (pu->client_closed() != closed) {
+	verbose_err("Server client socket close state (%s) "
+		    "does not matched expected (%s)\n",
+		    pu->client_closed() ? "true" : "false",
+		    closed ? "true" : "false");
+	*eflag = true;
+    }
+}
+
+//
+// ----------------------------------------------------------------------------
+// Client functions
+
+static void
+create_client(EventLoop*	pe,
+	      XrlSocketServer**	ppxss,
+	      IPv4		finder_host,
+	      uint16_t		finder_port,
+	      TestSocket4TCP**	ppu)
+{
+    XrlSocketServer* pxss = *ppxss;
+    verbose_log("Creating TestSocket4TCPClient instance.\n");
+    *ppu = new TestSocket4TCPClient(*pe, pxss->instance_name(),
+				    finder_host, finder_port);
+}
+
+static void
+bind_connect_client(TestSocket4TCP** ppu, IPv4 local_addr,
+		    uint16_t local_port, IPv4 remote_addr,
+		    uint16_t remote_port, bool *err)
+{
+    TestSocket4TCPClient* pu = dynamic_cast<TestSocket4TCPClient*>(*ppu);
+    bool s = pu->bind_connect(local_addr, local_port, remote_addr,
+    			      remote_port, false);
+    if (s == false)
+	*err = true;
+}
+
+
+static void
+close_client_socket(TestSocket4TCP** ppu)
+{
+    verbose_log("Closing client socket.\n");
+    TestSocket4TCPClient* pu = dynamic_cast<TestSocket4TCPClient*>(*ppu);
+    if (pu->close() == false) {
+	verbose_err("Failed to send close client socket request.\n");
+    }
+}
+
+static void
+verify_client_closed(TestSocket4TCP** ppu, bool closed, bool* eflag)
+{
+    TestSocket4TCPClient* pu = dynamic_cast<TestSocket4TCPClient*>(*ppu);
+    if (pu->closed() != closed) {
+	verbose_err("Client socket close state (%s) "
+		    "does not matched expected (%s)\n",
+		    pu->closed() ? "true" : "false",
+		    closed ? "true" : "false");
+	*eflag = true;
+    }
+}
+
+//
+// ----------------------------------------------------------------------------
+// Common functions
+
+
+static void
+destroy_test_socket(TestSocket4TCP** ppu)
+{
+    delete *ppu;
+    *ppu = 0;
+}
+
+static void
+start_sending(TestSocket4TCP** ppu)
+{
+    TestSocket4TCP* pu = *ppu;
+    pu->start_sending(512, 200);
+}
+
+static void
+stop_sending(TestSocket4TCP** ppu)
+{
+    TestSocket4TCP* pu = *ppu;
+    pu->stop_sending();
+}
+
+static void
+match_bytes_sent_received(TestSocket4TCP** pps /* sender */,
+			  TestSocket4TCP** ppr /* receiver */,
+			  bool* eflag)
+{
+    TestSocket4TCP* ps = *pps;
+    TestSocket4TCP* pr = *ppr;
+
+    if (ps->bytes_sent() != pr->bytes_received()) {
+	verbose_err("Bytes sender sent[%d] do not match bytes receiver "
+		    "received[%d]\n", ps->bytes_sent(), pr->bytes_received());
+	*eflag = true;
+    } else {
+    	verbose_log("Bytes sent equals bytes received.\n");
+    }
+}
+
+// ----------------------------------------------------------------------------
+// Test Main
+
+int
+test_main(IPv4 finder_host, uint16_t finder_port)
+{
+    EventLoop e;
+    TestAddressTable tat;
+
+    tat.add_address(IPv4::LOOPBACK());
+
+    vector<XorpTimer> ev;	// Vector for timed events
+    bool eflag(false);		// Error flag set by timed events
+
+    if (verbose())
+	ev.push_back(e.new_periodic_ms(100, callback(ticker)));
+
+    SchedulingTime stime;
+
+    //
+    // Create Socket server, check socket count.
+    //
+    XrlSocketServer* xss;
+    ev.push_back(e.new_oneoff_after_ms(stime.now(),
+			       callback(create_socket_server,
+					&e, &tat, finder_host,
+					finder_port, &xss)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(start_socket_server,
+					&xss)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_socket4_count,
+					&xss, 0, &eflag)));
+
+    //
+    // Create server, bind to port 5000, listen, check states.
+    //
+    TestSocket4TCP* server;
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(create_server,
+					&e, &xss, finder_host,
+					finder_port, &server)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_server_closed, &server,
+					true, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_server_client_closed, &server,
+					true, &eflag)));
+
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(bind_server, &server,
+					IPv4::LOOPBACK(), uint16_t(5000),
+					&eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(listen_server, &server,
+					uint16_t(2),
+					&eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_socket4_count,
+					&xss, 1, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_server_closed, &server,
+					false, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_server_client_closed, &server,
+					true, &eflag)));
+
+    //
+    // Create client and bind on port 5001, check state.
+    //
+    TestSocket4TCP* client;
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(create_client,
+					&e, &xss, finder_host,
+					finder_port, &client)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_client_closed, &client,
+					true, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_socket4_count,
+					&xss, 1, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(bind_connect_client, &client,
+					IPv4::LOOPBACK(), uint16_t(5001),
+					IPv4::LOOPBACK(), uint16_t(5000),
+					&eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_client_closed, &client,
+					false, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_socket4_count,
+					&xss, 3, &eflag)));
+
+    //
+    // Send packets from client to server, check bytes send/received and states
+    //
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(start_sending, &client)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(10000),
+			       callback(stop_sending, &client)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(match_bytes_sent_received,
+					&client, &server, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_client_closed, &client,
+					false, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_server_closed, &server,
+					false, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_server_client_closed, &server,
+					false, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_socket4_count,
+					&xss, 3, &eflag)));
+
+    //
+    // Send packets from server to client, check bytes send/received and states
+    //
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(start_sending, &server)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(10000),
+			       callback(stop_sending, &server)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(match_bytes_sent_received,
+					&server, &client, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_client_closed, &client,
+					false, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_server_closed, &server,
+					false, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_server_client_closed, &server,
+					false, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_socket4_count,
+					&xss, 3, &eflag)));
+
+    //
+    // Close/disconnect client, verify states
+    //
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(close_client_socket,
+					&client)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_client_closed, &client,
+					true, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_server_client_closed, &server,
+					true, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_server_closed, &server,
+					false, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_socket4_count,
+					&xss, 1, &eflag)));
+
+    //
+    // Invalidate IPv4::LOOPBACK(), which should cause server socket to
+    // be closed. Check states.
+    //
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(remove_address,
+					&tat, IPv4::LOOPBACK())));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_server_closed, &server,
+					true, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_socket4_count,
+					&xss, 0, &eflag)));
+
+    //
+    // Destroy client and server.
+    //
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(destroy_test_socket, &client)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(destroy_test_socket, &server)));
+
+    //
+    // Re-add loopback address, and check states.
+    //
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(add_address,
+					&tat, IPv4::LOOPBACK())));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_socket_owner_count,
+					&xss, 0, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_socket4_count,
+					&xss, 0, &eflag)));
+
+    //
+    // Create server and client again, and connect as before, and this time
+    // use the wildcard port 0 for the client.
+    //
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(create_server,
+					&e, &xss, finder_host,
+					finder_port, &server)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+    			       callback(bind_server, &server,
+    					IPv4::LOOPBACK(), uint16_t(5000),
+					&eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+    			       callback(listen_server, &server,
+    					uint16_t(2),
+					&eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(create_client,
+					&e, &xss, finder_host,
+					finder_port, &client)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+    			       callback(bind_connect_client, &client,
+					IPv4::LOOPBACK(), uint16_t(0),
+					IPv4::LOOPBACK(), uint16_t(5000),
+					&eflag)));
+
+    //
+    // Verify states, then close client socket on server
+    //
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+    			       callback(verify_client_closed, &client,
+					false, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+    			       callback(verify_server_closed, &server,
+					false, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+    			       callback(verify_server_client_closed, &server,
+					false, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_socket4_count,
+					&xss, 3, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(close_server_client_socket,
+					&server)));
+
+    //
+    // Verify states, then close the server socket
+    //
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+    			       callback(verify_client_closed, &client,
+					true, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+    			       callback(verify_server_closed, &server,
+					false, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+    			       callback(verify_server_client_closed, &server,
+					true, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+    			       callback(verify_socket4_count,
+					&xss, 1, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(close_server_socket,
+					&server)));
+
+    //
+    // Verify states, then destroy server and client
+    //
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_server_closed, &server,
+					true, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_socket4_count,
+					&xss, 0, &eflag)));
+
+
+    //
+    // Check socket server is holding no resources.
+    //
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_socket_owner_count,
+					&xss, 0, &eflag)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(verify_socket4_count,
+					&xss, 0, &eflag)));
+    //
+    // Shutdown socket server.
+    //
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(shutdown_socket_server,
+					&xss)));
+    //
+    // Destroy socket server.
+    //
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(destroy_socket_server,
+					&xss)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(destroy_test_socket, &client)));
+
+    ev.push_back(e.new_oneoff_after_ms(stime.next(),
+			       callback(destroy_test_socket, &server)));
+
+    //
+    // Force exit.
+    //
+    bool finish(false);
+    ev.push_back(e.set_flag_after_ms(stime.next(1000), &finish));
+
+    while (eflag == false && finish == false) {
+	e.run();
+    }
+
+    if (eflag)
+	return -1;
+
+    return 0;
+}
+
+
+
+/* ------------------------------------------------------------------------- */
+
+static void
+usage(const char* progname)
+{
+    fprintf(stderr, "usage: %s [-F <host>:<port>] [-v]\n", progname);
+    fprintf(stderr, "Options:\n");
+    fprintf(stderr, "  -F <host>[:<port>]  "
+            "Specify arguments for external Finder instance\n");
+    fprintf(stderr, "  -v                  Verbose output\n");
+    fprintf(stderr, "Runs remote TCP socket test using Xrls.\n");
+    exit(1);
+}
+
+
+static bool
+parse_finder_arg(const char* host_colon_port,
+		 IPv4&	     finder_addr,
+		 uint16_t&   finder_port)
+{
+    string finder_host;
+
+    const char* p = strstr(host_colon_port, ":");
+
+    if (p) {
+	finder_host = string(host_colon_port, p);
+	finder_port = atoi(p + 1);
+	if (finder_port == 0) {
+	    fprintf(stderr, "Invalid port \"%s\"\n", p + 1);
+	    return false;
+	}
+    } else {
+	finder_host = string(host_colon_port);
+	finder_port = FinderConstants::FINDER_DEFAULT_PORT();
+    }
+
+    try {
+	finder_addr = IPv4(finder_host.c_str());
+    } catch (const InvalidString& ) {
+	// host string may need resolving
+	in_addr ia;
+	if (address_lookup(finder_host, ia) == false) {
+	    fprintf(stderr, "Invalid host \"%s\"\n", finder_host.c_str());
+	    return false;
+	}
+	finder_addr.copy_in(ia);
+    }
+    return true;
+}
+
+// ----------------------------------------------------------------------------
+// Main
+
+int
+main(int argc, char* const argv[])
+{
+    //
+    // Initialize and start xlog
+    //
+    xlog_init(argv[0], NULL);
+    xlog_set_verbose(XLOG_VERBOSE_LOW);         // Least verbose messages
+    // XXX: verbosity of the error messages temporarily increased
+    xlog_level_set_verbose(XLOG_LEVEL_ERROR, XLOG_VERBOSE_HIGH);
+    xlog_add_default_output();
+    xlog_start();
+
+    IPv4        finder_addr = FinderConstants::FINDER_DEFAULT_HOST();
+    uint16_t    finder_port = FinderConstants::FINDER_DEFAULT_PORT();
+
+    int r = 0;	// Return code
+
+    int ch = 0;
+    while ((ch = getopt(argc, argv, "F:v")) != -1) {
+	switch (ch) {
+	case 'F':
+	    if (parse_finder_arg(optarg, finder_addr, finder_port) == false) {
+		usage(argv[0]);
+		r = 1;
+	    }
+	    break;
+	case 'v':
+	    set_verbose(true);
+	    break;
+	default:
+	    usage(argv[0]);
+	    r = 1;
+	}
+    }
+    argc -= optind;
+    argv += optind;
+
+    try {
+	if (r == 0) {
+	    r = test_main(finder_addr, finder_port);
+	}
+    }
+    catch (...) {
+	xorp_catch_standard_exceptions();
+    }
+    //
+    // Gracefully stop and exit xlog
+    //
+    xlog_stop();
+    xlog_exit();
+
+    return r;
+}
+
Index: fea/test_xrl_sockets4_tcp.sh
===================================================================
RCS file: fea/test_xrl_sockets4_tcp.sh
diff -N fea/test_xrl_sockets4_tcp.sh
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ fea/test_xrl_sockets4_tcp.sh	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+set -e
+
+# Conditionally set ${srcdir} if it wasn't assigned (e.g., by `gmake check`)
+if [ "X${srcdir}" = "X" ] ; then srcdir=`dirname $0` ; fi
+
+. ${srcdir}/../utils/xrl_shell_lib.sh
+
+test_xrl_sockets4_tcp()
+{
+    ./test_xrl_sockets4_tcp
+}
+
+TESTS="test_xrl_sockets4_tcp"
+
+# Include command line
+. ${srcdir}/../utils/args.sh
+
+if [ $START_PROGRAMS = "yes" ] ; then
+    CXRL="../libxipc/call_xrl -w 10 -r 10"
+    ../utils/runit $QUIET $VERBOSE -c "$0 -s -c $*" <<EOF
+    ../libxipc/xorp_finder = $CXRL finder://finder/finder/0.2/get_xrl_targets
+EOF
+    exit $?
+fi
+
+for t in ${TESTS} ; do
+    $t
+    _ret_value=$?
+    if [ ${_ret_value} -ne 0 ] ; then
+        echo
+        echo "$0: Tests Failed"
+        exit ${_ret_value}
+    fi
+done
+
+echo
+echo "$0: Tests Succeeded"
+exit 0
