diff --git a/src/xpdev/multisock.c b/src/xpdev/multisock.c
index a74038cbc0360cfe47501ff0ff542c75d2ac9755..0e85842af7a5dbe10d3ce84854bc9ab7aa220c71 100644
--- a/src/xpdev/multisock.c
+++ b/src/xpdev/multisock.c
@@ -134,6 +134,40 @@ BOOL xpms_add(struct xpms_set *xpms_set, int domain, int type,
 	return FALSE;
 }
 
+BOOL xpms_add_list(struct xpms_set *xpms_set, int domain, int type,
+	int protocol, str_list_t list, uint16_t default_port, const char *prot, 
+	void (*sock_init)(SOCKET, void *), int(*bind_init)(BOOL), void *cbdata)
+{
+	char	**iface;
+	char	*host;
+	char	*p, *p2;
+	BOOL	one_good=FALSE;
+	
+	for(iface=list; iface && *iface; iface++) {
+		host=strdup(*iface);
+		WORD	port=default_port;
+
+		if(xpms_set->lprintf)
+			xpms_set->lprintf(LOG_INFO, "Adding %s listening socket on %s", prot, host);
+		p = strrchr(host, ':');
+		if(host[0]=='[') {
+			p2=strrchr(host,']');
+			if(p2)
+				*p2=0;
+			if(p2 > p)
+				p=NULL;
+		}
+		if(p!=NULL) {
+			*(p++)=0;
+			sscanf(p, "%hu", &port);
+		}
+		if(xpms_add(xpms_set, PF_UNSPEC, SOCK_STREAM, 0, host, port, prot, sock_init, bind_init, NULL))
+			one_good=TRUE;
+		free(host);
+	}
+	return one_good;
+}
+
 SOCKET xpms_accept(struct xpms_set *xpms_set, struct sockaddr * addr, 
 	socklen_t * addrlen, unsigned int timeout, void **cb_data)
 {
@@ -184,3 +218,4 @@ SOCKET xpms_accept(struct xpms_set *xpms_set, struct sockaddr * addr,
 
 	return INVALID_SOCKET;
 }
+
diff --git a/src/xpdev/multisock.h b/src/xpdev/multisock.h
index ea73fa19e4dae01ee97cebdf97f0b7e5487d14fc..782104f38f2ab35327c649912e385856960bdd34 100644
--- a/src/xpdev/multisock.h
+++ b/src/xpdev/multisock.h
@@ -2,6 +2,7 @@
 #define MULTISOCK_H
 
 #include <sys/limits.h>
+#include <str_list.h>
 
 struct xpms_sockdef
 {
@@ -35,6 +36,9 @@ void xpms_destroy(struct xpms_set *xpms_set);
 BOOL xpms_add(struct xpms_set *xpms_set, int domain, int type,
 	int protocol, const char *addr, uint16_t port, const char *prot, 
 	void (*sock_init)(SOCKET, void *), int(*bind_init)(BOOL), void *cbdata);
+BOOL xpms_add_list(struct xpms_set *xpms_set, int domain, int type,
+	int protocol, str_list_t list, uint16_t default_port, const char *prot, 
+	void (*sock_init)(SOCKET, void *), int(*bind_init)(BOOL), void *cbdata);
 SOCKET xpms_accept(struct xpms_set *, struct sockaddr * addr, 
 	socklen_t * addrlen, unsigned int timeout, void **cb_data);
 
diff --git a/src/xpdev/sockwrap.c b/src/xpdev/sockwrap.c
index cfb9ac15ba338714108f682562c8dfdd74e32837..eb91b239c4798bb609b465aa7de357ec57e95cd6 100644
--- a/src/xpdev/sockwrap.c
+++ b/src/xpdev/sockwrap.c
@@ -386,3 +386,27 @@ int nonblocking_connect(SOCKET sock, struct sockaddr* addr, size_t size, unsigne
 	}
 	return result;
 }
+
+const char *inet_addrtop(SOCKADDR *in, char *dest, size_t size)
+{
+	switch(in->sa_family) {
+		case AF_INET:
+			return inet_ntop(in->sa_family, &((struct sockaddr_in *)in)->sin_addr, dest, size);
+		case AF_INET6:
+			return inet_ntop(in->sa_family, &((struct sockaddr_in6 *)in)->sin6_addr, dest, size);
+		default:
+			return NULL;
+	}
+}
+
+uint16_t inet_addrport(SOCKADDR *in)
+{
+	switch(in->sa_family) {
+		case AF_INET:
+			return ntohs(((struct sockaddr_in *)in)->sin_port);
+		case AF_INET6:
+			return ntohs(((struct sockaddr_in6 *)in)->sin6_port);
+		default:
+			return 0;
+	}
+}
diff --git a/src/xpdev/sockwrap.h b/src/xpdev/sockwrap.h
index f94ee97b647aa38b88b238bbca9794822a2eaf47..43412dd10d93f12ea9418f4d3017aaca69da2c0d 100644
--- a/src/xpdev/sockwrap.h
+++ b/src/xpdev/sockwrap.h
@@ -193,6 +193,8 @@ int 	retry_bind(SOCKET s, const struct sockaddr *addr, socklen_t addrlen
 				   ,uint retries, uint wait_secs, const char* prot
 				   ,int (*lprintf)(int level, const char *fmt, ...));
 int		nonblocking_connect(SOCKET, struct sockaddr*, size_t, unsigned timeout /* seconds */);
+const char *inet_addrtop(SOCKADDR *in, char *dest, size_t size);
+uint16_t inet_addrport(SOCKADDR *in);
 
 #ifdef __cplusplus
 }