opensips之fix_cmd_listeners()

本文介绍了一个用于枚举并修复服务器上所有IP地址及端口的函数`fix_all_socket_lists()`。该函数通过遍历不同协议类型的监听器列表,解决地址解析、接口名称转换等问题,并确保每个监听器配置正确无误。

枚举本服务器上的所有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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值