diff --git a/src/xpdev/multisock.c b/src/xpdev/multisock.c
new file mode 100644
index 0000000000000000000000000000000000000000..3ca1b24d06b09ffe5b01648f89ad52399334e729
--- /dev/null
+++ b/src/xpdev/multisock.c
@@ -0,0 +1,171 @@
+// Multi-socket versions ofthe socket API...
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gen_defs.h>
+#include <sockwrap.h>
+#include <multisock.h>
+
+struct xpms_set *xpms_create(unsigned int retries, unsigned int wait_secs,
+	int (*lprintf)(int level, const char *fmt, ...))
+{
+	struct xpms_set *ret=(struct xpms_set *)calloc(1, sizeof(struct xpms_set));
+
+	if(ret==NULL)
+		return ret;
+	ret->retries = retries;
+	ret->wait_secs = wait_secs;
+	ret->lprintf=lprintf;
+	return ret;
+}
+
+void xpms_destroy(struct xpms_set *xpms_set)
+{
+	int		i;
+
+	for(i=0; i<xpms_set->sock_count; i++) {
+		if(xpms_set->socks[i].sock != INVALID_SOCKET) {
+			if(xpms_set->lprintf!=NULL)
+				xpms_set->lprintf(LOG_INFO, "%04d closing %s socket on port %d"
+						, xpms_set->socks[i].sock, xpms_set->socks[i].prot?xpms_set->socks[i].prot:"unknown"
+						, xpms_set->socks[i].port);
+			closesocket(xpms_set->socks[i].sock);
+		}
+		xpms_set->socks[i].sock = INVALID_SOCKET;
+		FREE_AND_NULL(xpms_set->socks[i].address);
+		FREE_AND_NULL(xpms_set->socks[i].prot);
+	}
+	FREE_AND_NULL(xpms_set->socks);
+	free(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 *cbdata)
+{
+	struct xpms_sockdef	*new_socks;
+    struct addrinfo		hints;
+    struct addrinfo		*res;
+    struct addrinfo		*cur;
+    unsigned int		added = 0;
+    int					ret;
+    char				port_str[6];
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_flags=AI_PASSIVE;
+	hints.ai_family=domain;
+	hints.ai_socktype=type;
+	hints.ai_protocol=protocol;
+	hints.ai_flags=AI_NUMERICSERV;
+#ifdef AI_ADDRCONFIG
+	hints.ai_flags|=AI_ADDRCONFIG;
+#endif
+	sprintf(port_str, "%hu", port);
+	if((ret=getaddrinfo(addr, port_str, &hints, &res))!=0) {
+		if(xpms_set->lprintf)
+			xpms_set->lprintf(LOG_CRIT, "!ERROR %d calling getaddrinfo() on %s", ret, addr);
+		return FALSE;
+	}
+
+	for(cur=res; cur; cur=cur->ai_next) {
+		new_socks=(struct xpms_sockdef *)realloc(xpms_set->socks, sizeof(struct xpms_set)*xpms_set->sock_count+1);
+		if(new_socks==NULL) {
+			/* This may be a partial failure */
+			if(xpms_set->lprintf)
+				xpms_set->lprintf(LOG_CRIT, "!ERROR out of memory adding to multisocket");
+			if(added==0)
+				return FALSE;
+			return TRUE;
+		}
+		xpms_set->socks=new_socks;
+		xpms_set->socks[xpms_set->sock_count].address = strdup(addr);
+		xpms_set->socks[xpms_set->sock_count].cb_data = cbdata;
+		xpms_set->socks[xpms_set->sock_count].domain = cur->ai_family;	/* Address/Protocol Family */
+		xpms_set->socks[xpms_set->sock_count].type = cur->ai_socktype;
+		xpms_set->socks[xpms_set->sock_count].protocol = protocol;
+		xpms_set->socks[xpms_set->sock_count].port = port;
+		xpms_set->socks[xpms_set->sock_count].prot = strdup(prot);
+		xpms_set->socks[xpms_set->sock_count].sock = socket(cur->ai_family, cur->ai_socktype, protocol);
+		if(xpms_set->socks[xpms_set->sock_count].sock == INVALID_SOCKET) {
+			FREE_AND_NULL(xpms_set->socks[xpms_set->sock_count].address);
+			FREE_AND_NULL(xpms_set->socks[xpms_set->sock_count].prot);
+			continue;
+		}
+
+		if(retry_bind(xpms_set->socks[xpms_set->sock_count].sock, cur->ai_addr, cur->ai_addrlen, xpms_set->retries, xpms_set->wait_secs, prot, xpms_set->lprintf)==-1) {
+			closesocket(xpms_set->socks[xpms_set->sock_count].sock);
+			FREE_AND_NULL(xpms_set->socks[xpms_set->sock_count].address);
+			FREE_AND_NULL(xpms_set->socks[xpms_set->sock_count].prot);
+			continue;
+		}
+
+		if(!listen(xpms_set->socks[xpms_set->sock_count].sock, SOMAXCONN)) {
+			if(xpms_set->lprintf)
+				xpms_set->lprintf(LOG_WARNING, "%04d !ERROR %d listen()ing op port %d"
+						, xpms_set->socks[xpms_set->sock_count].sock, ERROR_VALUE, port);
+			closesocket(xpms_set->socks[xpms_set->sock_count].sock);
+			FREE_AND_NULL(xpms_set->socks[xpms_set->sock_count].address);
+			FREE_AND_NULL(xpms_set->socks[xpms_set->sock_count].prot);
+			continue;
+		}
+
+		added++;
+		xpms_set->sock_count++;
+	}
+
+	if(added)
+		return TRUE;
+	return FALSE;
+}
+
+SOCKET xpms_accept(struct xpms_set *xpms_set, struct sockaddr * addr, 
+	socklen_t * addrlen, unsigned int timeout, void **cb_data)
+{
+	fd_set			read_fs;
+	fd_set			except_fs;
+	int				i;
+	struct timeval	tv;
+	struct timeval	*tvp;
+	SOCKET			max_sock=0;
+	
+	FD_ZERO(&read_fs);
+	for(i=0; i<xpms_set->sock_count; i++) {
+		if(xpms_set->socks[i].sock == INVALID_SOCKET)
+			continue;
+		FD_SET(xpms_set->socks[i].sock, &read_fs);
+		FD_SET(xpms_set->socks[i].sock, &except_fs);
+		if(xpms_set->socks[i].sock > max_sock)
+			max_sock=xpms_set->socks[i].sock+1;
+	}
+
+	if(timeout==XPMS_FOREVER)
+		tvp=NULL;
+	else {
+		tv.tv_sec=timeout/1000;
+		tv.tv_usec=(timeout%1000)*1000;
+		tvp=&tv;
+	}
+	switch(select(max_sock, &read_fs, NULL, &except_fs, tvp)) {
+		case 0:
+			return INVALID_SOCKET;
+		case -1:
+			return SOCKET_ERROR;
+		default:
+			for(i=0; i<xpms_set->sock_count; i++) {
+				if(xpms_set->socks[i].sock == INVALID_SOCKET)
+					continue;
+				if(FD_ISSET(xpms_set->socks[i].sock, &read_fs)) {
+					if(cb_data)
+						*cb_data=xpms_set->socks[i].cb_data;
+					return accept(xpms_set->socks[i].sock, addr, addrlen);
+				}
+				if(FD_ISSET(xpms_set->socks[i].sock, &except_fs)) {
+					closesocket(xpms_set->socks[i].sock);
+					xpms_set->socks[i].sock = INVALID_SOCKET;
+				}
+			}
+	}
+
+	return INVALID_SOCKET;
+}
diff --git a/src/xpdev/multisock.h b/src/xpdev/multisock.h
new file mode 100644
index 0000000000000000000000000000000000000000..2441b979b1fcaebb599dd6edb7cbc5bb613b2f4a
--- /dev/null
+++ b/src/xpdev/multisock.h
@@ -0,0 +1,37 @@
+#ifndef MULTISOCK_H
+#define MULTISOCK_H
+
+#include <sys/limits.h>
+
+struct xpms_sockdef
+{
+	void			*cb_data;
+	int				domain;
+	int				type;
+	int				protocol;
+	SOCKET			sock;
+	char			*address;
+	uint16_t		port;
+	char			*prot;
+};
+
+struct xpms_set {
+	struct xpms_sockdef	*socks;
+	int					(*lprintf)(int level, const char *fmt, ...);
+	size_t				sock_count;
+	unsigned int		retries;
+	unsigned int		wait_secs;
+};
+
+#define XPMS_FOREVER	UINT_MAX
+
+struct xpms_set *xpms_create(unsigned int retries, unsigned int wait_secs,
+	int (*lprintf)(int level, const char *fmt, ...));
+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 *cbdata);
+SOCKET xpms_accept(struct xpms_set *, struct sockaddr * addr, 
+	socklen_t * addrlen, unsigned int timeout, void **cb_data);
+
+#endif
diff --git a/src/xpdev/objects.mk b/src/xpdev/objects.mk
index ec0e4dcf2d039e685a10363cd0523d8e4f2f0060..6cccb5385ac05a91ac6a7eac5d4ea10b4e9ba350 100644
--- a/src/xpdev/objects.mk
+++ b/src/xpdev/objects.mk
@@ -15,6 +15,7 @@ OBJS	= \
 	$(OBJODIR)$(DIRSEP)genwrap$(OFILE) \
 	$(OBJODIR)$(DIRSEP)ini_file$(OFILE) \
 	$(OBJODIR)$(DIRSEP)link_list$(OFILE) \
+	$(OBJODIR)$(DIRSEP)multisock$(OFILE) \
 	$(OBJODIR)$(DIRSEP)netwrap$(OFILE) \
 	$(OBJODIR)$(DIRSEP)sockwrap$(OFILE) \
 	$(OBJODIR)$(DIRSEP)semfile$(OFILE) \
@@ -37,6 +38,7 @@ MTOBJS	= \
 	$(MTOBJODIR)$(DIRSEP)ini_file$(OFILE) \
 	$(MTOBJODIR)$(DIRSEP)link_list$(OFILE) \
 	$(MTOBJODIR)$(DIRSEP)msg_queue$(OFILE) \
+	$(MTOBJODIR)$(DIRSEP)multisock$(OFILE) \
 	$(MTOBJODIR)$(DIRSEP)semwrap$(OFILE) \
 	$(MTOBJODIR)$(DIRSEP)netwrap$(OFILE) \
 	$(MTOBJODIR)$(DIRSEP)sockwrap$(OFILE) \