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) \