/* adds a sock_info structure to the corresponding proto list * return 0 on success, -1 on error */ int add_listen_iface(char* name, unsigned short port, unsigned short proto, enum si_flags flags) { struct socket_info** list; unsigned short c_proto; c_proto=(proto)?proto:PROTO_UDP; do{ list=get_sock_info_list(c_proto); if (list==0){ LOG(L_ERR, "ERROR: add_listen_iface: get_sock_info_list failed\n"); goto error; } if (port==0){ /* use default port */ port= #ifdef USE_TLS ((c_proto)==PROTO_TLS)?tls_port_no: #endif port_no; } #ifdef USE_TLS else if ((c_proto==PROTO_TLS) && (proto==0)){ /* -l ip:port => on udp:ip:port; tcp:ip:port and tls:ip:port+1? */ port++; } #endif if (new_sock2list(name, port, c_proto, flags, list)<0){ LOG(L_ERR, "ERROR: add_listen_iface: new_sock2list failed\n"); goto error; } }while( (proto==0) && (c_proto=next_proto(c_proto))); return 0; error: return -1; }
int add_listener(struct socket_id *sock, enum si_flags flags) { /* * XXX: using the new version, the protocol _MUST_ be specified * otherwise UDP will be assumed */ enum sip_protos proto = sock->proto; /* validate the protocol */ if (proto < PROTO_FIRST || proto >= PROTO_LAST) { LM_BUG("invalid protocol number %d\n", proto); return -1; } /* convert to socket_info */ if (new_sock2list(sock->name, sock->port, sock->proto, sock->adv_name, sock->adv_port, sock->children, flags, &protos[proto].listeners) < 0) { LM_ERR("cannot add socket to the list\n"); return -1; } return 0; }
/* add all family type addresses of interface if_name to the socket_info array * if if_name==0, adds all addresses on all interfaces * WARNING: it only works with ipv6 addresses on FreeBSD * return: -1 on error, 0 on success */ int add_interfaces(char* if_name, int family, unsigned short port, unsigned short proto, struct socket_info** list) { struct ifconf ifc; struct ifreq ifr; struct ifreq ifrcopy; char* last; char* p; int size; int lastlen; int s; char* tmp; struct ip_addr addr; int ret; enum si_flags flags; #ifdef HAVE_SOCKADDR_SA_LEN #ifndef MAX #define MAX(a,b) ( ((a)>(b))?(a):(b)) #endif #endif /* ipv4 or ipv6 only*/ flags=SI_NONE; s=socket(family, SOCK_DGRAM, 0); ret=-1; lastlen=0; ifc.ifc_req=0; for (size=100; ; size*=2){ ifc.ifc_len=size*sizeof(struct ifreq); ifc.ifc_req=(struct ifreq*) pkg_malloc(size*sizeof(struct ifreq)); if (ifc.ifc_req==0){ LOG(L_ERR, "ERROR: add_interfaces: memory allocation failure\n"); goto error; } if (ioctl(s, SIOCGIFCONF, &ifc)==-1){ if(errno==EBADF) return 0; /* invalid descriptor => no such ifs*/ LOG(L_ERR, "ERROR: add_interfaces: ioctl failed: %s\n", strerror(errno)); goto error; } if ((lastlen) && (ifc.ifc_len==lastlen)) break; /*success, len not changed*/ lastlen=ifc.ifc_len; /* try a bigger array*/ pkg_free(ifc.ifc_req); } last=(char*)ifc.ifc_req+ifc.ifc_len; for(p=(char*)ifc.ifc_req; p<last; p+= #ifdef __OS_linux sizeof(ifr) /* works on x86_64 too */ #else (sizeof(ifr.ifr_name)+ #ifdef HAVE_SOCKADDR_SA_LEN MAX(ifr.ifr_addr.sa_len, sizeof(struct sockaddr)) #else ( (ifr.ifr_addr.sa_family==AF_INET)? sizeof(struct sockaddr_in): ((ifr.ifr_addr.sa_family==AF_INET6)? sizeof(struct sockaddr_in6):sizeof(struct sockaddr)) ) #endif ) #endif ) { /* copy contents into ifr structure * warning: it might be longer (e.g. ipv6 address) */ memcpy(&ifr, p, sizeof(ifr)); if (ifr.ifr_addr.sa_family!=family){ /*printf("strange family %d skipping...\n", ifr->ifr_addr.sa_family);*/ continue; } /*get flags*/ ifrcopy=ifr; if (ioctl(s, SIOCGIFFLAGS, &ifrcopy)!=-1){ /* ignore errors */ /* ignore down ifs only if listening on all of them*/ if (if_name==0){ /* if if not up, skip it*/ if (!(ifrcopy.ifr_flags & IFF_UP)) continue; } } if ((if_name==0)|| (strncmp(if_name, ifr.ifr_name, sizeof(ifr.ifr_name))==0)){ /*add address*/ sockaddr2ip_addr(&addr, (struct sockaddr*)(p+(long)&((struct ifreq*)0)->ifr_addr)); if ((tmp=ip_addr2a(&addr))==0) goto error; /* check if loopback */ if (ifrcopy.ifr_flags & IFF_LOOPBACK) flags|=SI_IS_LO; /* add it to one of the lists */ if (new_sock2list(tmp, port, proto, flags, list)!=0){ LOG(L_ERR, "ERROR: add_interfaces: new_sock2list failed\n"); goto error; } ret=0; } /* printf("%s:\n", ifr->ifr_name); printf(" "); print_sockaddr(&(ifr->ifr_addr)); printf(" "); ls_ifflags(ifr->ifr_name, family, options); printf("\n");*/ } pkg_free(ifc.ifc_req); /*clean up*/ close(s); return ret; error: if (ifc.ifc_req) pkg_free(ifc.ifc_req); close(s); return -1; }