枚举本服务器上的所有ip和本服务端口
fix_all_socket_lists();
/*return 0 on success, -1 on error */
int fix_all_socket_lists(void)
{
int i;
int found = 0;
static char buf[5 /* currently sctp\0 is the largest protocol */];
char *p;
for (i = PROTO_FIRST; i < PROTO_LAST; i++) {
if (protos[i].id != PROTO_NONE) {
if (fix_socket_list(&protos[i].listeners)!=0) {
LM_ERR("fix_socket_list for %d failed\n", protos[i].id);
goto error;
}
found++;
} else if (protos[i].listeners) {
p = proto2str(i, buf);
if (p == NULL)
goto error;
*p = '\0';
LM_ERR("listeners found for protocol %s, but no module "
"can handle it\n", buf);
goto error;
}
}
if (!found){
LM_ERR("no listening sockets\n");
goto error;
}
return 0;
error:
return -1;
}
/* function will write the proto as string, starting from the p pointer. The
new resulting proto will be returned (where writing ended) */
static inline char* proto2str(int proto, char *p)
{
switch (proto) {
case PROTO_UDP:
*(p++) = 'u';
*(p++) = 'd';
*(p++) = 'p';
break;
case PROTO_TCP:
*(p++) = 't';
*(p++) = 'c';
*(p++) = 'p';
break;
case PROTO_TLS:
*(p++) = 't';
*(p++) = 'l';
*(p++) = 's';
break;
case PROTO_SCTP:
*(p++) = 's';
*(p++) = 'c';
*(p++) = 't';
*(p++) = 'p';
break;
case PROTO_WS:
*(p++) = 'w';
*(p++) = 's';
break;
default:
LM_CRIT("unsupported proto %d\n", proto);
return 0;
}
return p;
/* fixes a socket list => resolve addresses,
* interface names, fills missing members, remove duplicates */
int fix_socket_list(struct socket_info **list)
{
struct socket_info* si;
struct socket_info* l;
struct socket_info* next;
char* tmp;
int len;
struct hostent* he;
char** h;
/* try to change all the interface names into addresses
* --ugly hack */
for (si=*list;si;){
next=si->next;
if (add_interfaces(si->name.s, AF_INET, si->port_no,
si->proto, list)!=-1){
/* success => remove current entry (shift the entire array)*/
sock_listrm(list, si);
free_sock_info(si);
}
si=next;
}
/* get ips & fill the port numbers*/
for (si=*list;si;si=si->next){
/* fix the number of processes per interface */
if (!si->children && is_udp_based_proto(si->proto))
si->children = children_no;
if (si->port_no==0)
si->port_no= protos[si->proto].default_port;
tmp=int2str(si->port_no, &len);
if (len>=MAX_PORT_LEN){
LM_ERR("bad port number: %d\n", si->port_no);
goto error;
}
si->port_no_str.s=(char*)pkg_malloc(len+1);
if (si->port_no_str.s==0){
LM_ERR("out of pkg memory.\n");
goto error;
}
strncpy(si->port_no_str.s, tmp, len+1);
si->port_no_str.len=len;
/* get "official hostnames", all the aliases etc. */
he=resolvehost(si->name.s,0);
if (he==0){
LM_ERR("could not resolve %s\n", si->name.s);
goto error;
}
/* check if we got the official name */
if (strcasecmp(he->h_name, si->name.s)!=0){
if (auto_aliases && add_alias(si->name.s, si->name.len,
si->port_no, si->proto)<0){
LM_ERR("add_alias failed\n");
}
/* change the official name */
pkg_free(si->name.s);
si->name.s=(char*)pkg_malloc(strlen(he->h_name)+1);
if (si->name.s==0){
LM_ERR("out of pkg memory.\n");
goto error;
}
si->name.len=strlen(he->h_name);
strncpy(si->name.s, he->h_name, si->name.len+1);
}
/* add the aliases*/
if (auto_aliases) {
for(h=he->h_aliases; h && *h; h++)
if (add_alias(*h, strlen(*h), si->port_no, si->proto)<0){
LM_ERR("add_alias failed\n");
}
}
hostent2ip_addr(&si->address, he, 0); /*convert to ip_addr
format*/
if ((tmp=ip_addr2a(&si->address))==0) goto error;
if (si->address.af == AF_INET6) {
si->address_str.s=(char*)pkg_malloc(strlen(tmp)+1+2);
if (si->address_str.s==0){
LM_ERR("out of pkg memory.\n");
goto error;
}
si->address_str.s[0] = '[';
strncpy( si->address_str.s+1 , tmp, strlen(tmp));
si->address_str.s[1+strlen(tmp)] = ']';
si->address_str.s[2+strlen(tmp)] = '\0';
si->address_str.len=strlen(tmp) + 2;
} else {
si->address_str.s=(char*)pkg_malloc(strlen(tmp)+1);
if (si->address_str.s==0){
LM_ERR("out of pkg memory.\n");
goto error;
}
strncpy(si->address_str.s, tmp, strlen(tmp)+1);
si->address_str.len=strlen(tmp);
}
/* set is_ip (1 if name is an ip address, 0 otherwise) */
if ( auto_aliases && (si->address_str.len==si->name.len) &&
(strncasecmp(si->address_str.s, si->name.s,
si->address_str.len)==0)
){
si->flags|=SI_IS_IP;
/* do rev. DNS on it (for aliases)*/
he=rev_resolvehost(&si->address);
if (he==0){
LM_WARN("could not rev. resolve %s\n", si->name.s);
}else{
/* add the aliases*/
if (add_alias(he->h_name, strlen(he->h_name),
si->port_no, si->proto)<0){
LM_ERR("add_alias failed\n");
}
for(h=he->h_aliases; h && *h; h++)
if (add_alias(*h,strlen(*h),si->port_no,si->proto)<0){
LM_ERR(" add_alias failed\n");
}
}
}
/* Now build an ip_addr structure for the adv_name, if there is one
* so that find_si can find it later easily. Doing this so that
* we can force_send_socket() on an advertised name. Generally there
* is little interest in dealing with an advertised name as anything
* other than an opaque string that we blindly put into the SIP
* message.
*/
if(si->adv_name_str.len) {
/* If adv_name_str is already an IP, this is kinda foolish cus it
* converts it to ip_addr, then to he, then here we go back to
* ip_addr, but it's either that, or we duplicate the logic to
* check for an ip address here, and still we might have to call
* resolvehost().
*/
he=resolvehost(si->adv_name_str.s,0);
if (he==0){
LM_ERR("ERROR: fix_socket_list: could not resolve "
"advertised name %s\n", si->adv_name_str.s);
goto error;
}
hostent2ip_addr(&si->adv_address, he, 0); /*convert to ip_addr */
/* build and set string encoding for the adv socket info
* This is usefful for the usrloc module when it's generating
* or updating the socket on a location record, so we'll generate
* it up front just like the regular sock_str so we don't have
* to worry about it later.
*/
tmp = socket2str( si, 0, &si->adv_sock_str.len, 1);
if (tmp==0) {
LM_ERR("ERROR: fix_socket_list: failed to convert "
"socket to string (adv)\n");
goto error;
}
si->adv_sock_str.s=(char*)pkg_malloc(si->adv_sock_str.len);
if (si->adv_sock_str.s==0) {
LM_ERR("ERROR: fix_socket_list: out of memory.\n");
goto error;
}
memcpy(si->adv_sock_str.s, tmp, si->adv_sock_str.len);
}
/* build and set string encoding for the real socket info */
tmp = socket2str( si, 0, &si->sock_str.len, 0);
if (tmp==0) {
LM_ERR("failed to convert socket to string");
goto error;
}
si->sock_str.s=(char*)pkg_malloc(si->sock_str.len);
if (si->sock_str.s==0) {
LM_ERR("out of pkg memory.\n");
goto error;
}
memcpy(si->sock_str.s, tmp, si->sock_str.len);
#ifdef USE_MCAST
/* Check if it is an multicast address and
* set the flag if so
*/
if (is_mcast(&si->address)) {
si->flags |= SI_IS_MCAST;
}
#endif /* USE_MCAST */
#ifdef EXTRA_DEBUG
printf(" %.*s [%s]:%s%s\n", si->name.len,
si->name.s, si->address_str.s, si->port_no_str.s,
si->flags & SI_IS_MCAST ? " mcast" : "");
#endif
}
/* removing duplicate addresses*/
for (si=*list;si; si=si->next){
for (l=si->next;l;){
next=l->next;
if ((si->port_no==l->port_no) &&
(si->address.af==l->address.af) &&
(memcmp(si->address.u.addr, l->address.u.addr, si->address.len)
== 0)
){
#ifdef EXTRA_DEBUG
printf("removing duplicate %s [%s] == %s [%s]\n",
si->name.s, si->address_str.s,
l->name.s, l->address_str.s);
#endif
/* add the name to the alias list*/
if ((!(l->flags& SI_IS_IP)) && (
(l->name.len!=si->name.len)||
(strncmp(l->name.s, si->name.s, si->name.len)!=0))
)
add_alias(l->name.s, l->name.len, l->port_no, l->proto);
/* remove l*/
sock_listrm(list, l);
free_sock_info(l);
}
l=next;
}
}
#ifdef USE_MCAST
/* Remove invalid multicast entries */
si=*list;
while(si){
if ((si->flags & SI_IS_MCAST) &&
(si->proto != PROTO_UDP)
){
LM_WARN("removing entry %s:%s [%s]:%s\n",
get_proto_name(si->proto), si->name.s,
si->address_str.s, si->port_no_str.s);
l = si;
si=si->next;
sock_listrm(list, l);
free_sock_info(l);
} else {
si=si->next;
}
}
#endif /* USE_MCAST */
return 0;
error:
return -1;
}