BOOL DLLCALL 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) { struct xpms_sockdef *new_socks; struct addrinfo hints; struct addrinfo *res=NULL; struct addrinfo *cur; unsigned int added = 0; int ret; char port_str[6]; #ifndef _WIN32 struct addrinfo dummy; struct sockaddr_un un_addr; if(domain == AF_UNIX) { memset(&dummy, 0, sizeof(dummy)); dummy.ai_family = AF_UNIX; dummy.ai_socktype = type; dummy.ai_addr = (struct sockaddr *)&un_addr; un_addr.sun_family=AF_UNIX; if(strlen(addr) >= sizeof(un_addr.sun_path)) { if(xpms_set->lprintf) xpms_set->lprintf(LOG_ERR, "!ERROR %s is too long for a portable AF_UNIX socket", addr); return FALSE; } strcpy(un_addr.sun_path,addr); if(fexist(addr)) unlink(addr); dummy.ai_addrlen = sizeof(un_addr); un_addr.sun_len=SUN_LEN(&un_addr); res = &dummy; } #endif if(res == NULL) { 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_sockdef)*(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"); break; } 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(sock_init) sock_init(xpms_set->socks[xpms_set->sock_count].sock, cbdata); if(bind_init) { if(port < IPPORT_RESERVED && port > 0) bind_init(FALSE); } 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); if(bind_init) { if(port < IPPORT_RESERVED) bind_init(TRUE); } continue; } if(bind_init) { if(port < IPPORT_RESERVED && port > 0) bind_init(TRUE); } if(type != SOCK_DGRAM) { if(listen(xpms_set->socks[xpms_set->sock_count].sock, SOMAXCONN)==-1) { if(xpms_set->lprintf) xpms_set->lprintf(LOG_WARNING, "%04d !ERROR %d listen()ing on 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++; } #ifndef _WIN32 if(res != &dummy) #endif freeaddrinfo(res); if(added) return TRUE; return FALSE; }
static OptionBinding* bind_new(void) { OptionBinding *bind = malloc(sizeof(OptionBinding)); bind_init(bind); return bind; }