Esempio n. 1
0
/*
 * SIP_ADD_MYVIA
 *
 * interface == IF_OUTBOUND, IF_INBOUND
 *
 * RETURNS
 *	STS_SUCCESS on success
 *	STS_FAILURE on error
 */
int sip_add_myvia (sip_ticket_t *ticket, int interface,
		   struct in_addr *local_ip) {
   struct in_addr addr;
   char tmp[URL_STRING_SIZE] = {0};
   osip_via_t *via;
   int sts;
   char branch_id[VIA_BRANCH_SIZE];

   if (local_ip == NULL) {
      if (interface == IF_OUTBOUND) {
         if (get_ip_by_ifname(configuration.outbound_if, &addr) != STS_SUCCESS) {
            ERROR("can't find interface %s - configuration error?",
                configuration.outbound_if);
            return STS_FAILURE;
         }
      } else {
         if (get_ip_by_ifname(configuration.inbound_if, &addr) != STS_SUCCESS) {
            ERROR("can't find inbound interface %s - configuration error?",
                configuration.inbound_if);
            return STS_FAILURE;
         }
      }
   } else {
      addr = *local_ip;
   }


   sts = sip_calculate_branch_id(ticket, branch_id);

   snprintf(tmp,URL_STRING_SIZE, "SIP/2.0/UDP %s:%i;branch=%s;", utils_inet_ntoa(addr),
           configuration.sip_listen_port, branch_id);
   DEBUGC(DBCLASS_BABBLE,"adding VIA:%s",tmp);

   sts = osip_via_init(&via);
   if (sts!=0) return STS_FAILURE; /* allocation failed */

   sts = osip_via_parse(via, tmp);
   if (sts!=0) return STS_FAILURE;

   osip_list_add(ticket->sipmsg->vias,via,0);

   return STS_SUCCESS;
}
Esempio n. 2
0
/*
 * get_interface_real_ip:
 * fetches the real IP address of my interface INBOUND/OUTBOUND
 *
 * STS_SUCCESS on returning a valid IP and interface is UP
 * STS_FAILURE if interface is DOWN or other problem
 */
int  get_interface_real_ip(int interface, struct in_addr *retaddr) {
   int sts=STS_FAILURE;
   char *tmp=NULL;

      if (interface == IF_INBOUND) {
         tmp = configuration.inbound_if;
      } else if (interface == IF_OUTBOUND) {
         tmp = configuration.outbound_if;
      }

   if (tmp && (strcmp(tmp, "")!=0)) {
      DEBUGC(DBCLASS_DNS, "fetching interface IP by INTERFACE [%i]", interface);
      sts = get_ip_by_ifname(tmp, retaddr);
      if (sts != STS_SUCCESS) {
         ERROR("can't find interface %s - configuration error?", tmp);
      }

   } else {
      ERROR("Don't know what interface to look for - configuration error?");
   }

   return sts;
}
Esempio n. 3
0
/*
 * check if a given request is addressed to local. I.e. it is addressed
 * to the proxy itself (IP of my inbound or outbound interface, same port)
 *
 * RETURNS
 *	STS_TRUE if the request is addressed local
 *	STS_FALSE otherwise
 */
int is_sipuri_local (sip_ticket_t *ticket) {
   osip_message_t *sip=ticket->sipmsg;
   int found;
   struct in_addr addr_uri, addr_myself;
   char *my_interfaces[]=
        { configuration.inbound_if,  configuration.outbound_if,  (char*)-1 };
   int port;
   int i;
   char *ptr;

   if (sip==NULL) {
      ERROR("called is_sipuri_local with NULL sip");
      return STS_FALSE;
   }

   if (!sip || !sip->req_uri) {
      ERROR("is_sipuri_local: no request URI present");
      return STS_FALSE;
   }

   DEBUGC(DBCLASS_DNS,"check for local SIP URI %s:%s",
          sip->req_uri->host? sip->req_uri->host : "*NULL*",
          sip->req_uri->port? sip->req_uri->port : "*NULL*");

   if (utils_inet_aton(sip->req_uri->host, &addr_uri) == 0) {
      /* need name resolution */
      get_ip_by_host(sip->req_uri->host, &addr_uri);
   }   

   found=0;
   for (i=0; ; i++) {
      /*
       * try to search by interface name first
       */
      ptr=my_interfaces[i];
      if (ptr==(char*)-1) break; /* end of list mark */

      if (ptr) {
         DEBUGC(DBCLASS_BABBLE,"resolving IP of interface %s",ptr);
         if (get_ip_by_ifname(ptr, &addr_myself) != STS_SUCCESS) {
            ERROR("can't find interface %s - configuration error?", ptr);
            continue;
         }
      }

      /* check the extracted HOST against my own host addresses */
      if (sip->req_uri->port) {
         port=atoi(sip->req_uri->port);
      } else {
         port=SIP_PORT;
      }

      if ( (memcmp(&addr_myself, &addr_uri, sizeof(addr_myself))==0) &&
           (port == configuration.sip_listen_port) ) {
         DEBUG("address match [%s]", utils_inet_ntoa(addr_uri));
         found=1;
	 break;
      }
   }

   DEBUGC(DBCLASS_DNS, "SIP URI is %slocal", found? "":"not ");
   return (found)? STS_TRUE : STS_FALSE;
}
Esempio n. 4
0
/*
 * check if a given osip_via_t is local. I.e. its address is owned
 * by my inbound or outbound interface
 *
 * RETURNS
 *	STS_TRUE if the given VIA is one of my interfaces
 *	STS_FALSE otherwise
 */
int is_via_local (osip_via_t *via, struct in_addr *local_ip) {
   int sts, found;
   struct in_addr addr_via, addr_myself;
   char *my_interfaces[]=
        { configuration.inbound_if,  configuration.outbound_if,  (char*)-1 };
   int port;
   int i;
   char *ptr;

   if (via==NULL) {
      ERROR("called is_via_local with NULL via");
      return STS_FALSE;
   }

   DEBUGC(DBCLASS_BABBLE,"via name %s",via->host);
   if (utils_inet_aton(via->host,&addr_via) == 0) {
      /* need name resolution */
      sts=get_ip_by_host(via->host, &addr_via);
      if (sts == STS_FAILURE) {
         DEBUGC(DBCLASS_DNS, "is_via_local: cannot resolve VIA [%s]",
                via->host);
         return STS_FAILURE;
      }
   }   

   /* check the extracted VIA against my own host addresses */
   if (via->port) port=atoi(via->port);
   else port=SIP_PORT;

   /* Check local_ip if defined */
   if (local_ip) {
      if ( (memcmp(&addr_via, local_ip, sizeof(addr_via))==0) &&
           (port == configuration.sip_listen_port) ) {
         DEBUGC(DBCLASS_BABBLE,"via is local due to local_ip");
         return STS_TRUE;
      }
   }

   found=0;
   for (i=0; ; i++) {
      /*
       * try to search by interface name first
       */
      ptr=my_interfaces[i];
      if (ptr==(char*)-1) break; /* end of list mark */

      if (ptr) {
         DEBUGC(DBCLASS_BABBLE,"resolving IP of interface %s",ptr);
         if (get_ip_by_ifname(ptr, &addr_myself) != STS_SUCCESS) {
            ERROR("can't find interface %s - configuration error?", ptr);
            continue;
         }
      }

      if ( (memcmp(&addr_myself, &addr_via, sizeof(addr_myself))==0) &&
           (port == configuration.sip_listen_port) ) {
         DEBUG("got address match [%s]", utils_inet_ntoa(addr_via));
         found=1;
	 break;
      }
   }

   return (found)? STS_TRUE : STS_FALSE;
}
Esempio n. 5
0
int main (int argc, char *argv[]) 
#endif
{
   int sts;
   int i;
   int access;
   char buff [BUFFER_SIZE];
   sip_ticket_t ticket;

   extern char *optarg;		/* Defined in libc getopt and unistd.h */
   int ch1;
   
   char configfile[64]="siproxd";	/* basename of configfile */
   int  config_search=1;		/* search the config file */
   int  cmdline_debuglevel=0;
   char *pidfilename=NULL;
   struct sigaction act;

   log_set_stderr(1);

/*
 * setup signal handlers
 */
   act.sa_handler=sighandler;
   sigemptyset(&act.sa_mask);
   act.sa_flags=SA_RESTART;
   if (sigaction(SIGTERM, &act, NULL)) {
      ERROR("Failed to install SIGTERM handler");
   }
   if (sigaction(SIGINT, &act, NULL)) {
      ERROR("Failed to install SIGINT handler");
   }
   if (sigaction(SIGUSR2, &act, NULL)) {
      ERROR("Failed to install SIGUSR2 handler");
   }


/*
 * prepare default configuration
 */
   make_default_config();

   log_set_pattern(configuration.debuglevel);      

/*
 * open a the pwfile instance, so we still have access after
 * we possibly have chroot()ed to somewhere.
 */
   if (configuration.proxy_auth_pwfile) {
      siproxd_passwordfile = fopen(configuration.proxy_auth_pwfile, "r");
   } else {
      siproxd_passwordfile = NULL;
   }

/*
 * parse command line
 */
{
#ifdef	HAVE_GETOPT_LONG
   int option_index = 0;
   static struct option long_options[] = {
      {"help", no_argument, NULL, 'h'},
      {"config", required_argument, NULL, 'c'},
      {"debug", required_argument, NULL, 'd'},
      {"pid-file", required_argument, NULL,'p'},
      {0,0,0,0}
   };

    while ((ch1 = getopt_long(argc, argv, "hc:d:p:",
                  long_options, &option_index)) != -1) {
#else	/* ! HAVE_GETOPT_LONG */
    while ((ch1 = getopt(argc, argv, "hc:d:p:")) != -1) {
#endif
      switch (ch1) {
      case 'h':	/* help */
         DEBUGC(DBCLASS_CONFIG,"option: help");
         fprintf(stderr,str_helpmsg);
         exit(0);
	 break;

      case 'c':	/* load config file */
         DEBUGC(DBCLASS_CONFIG,"option: config file=%s",optarg);
         i=sizeof(configfile)-1;
         strncpy(configfile,optarg,i-1);
	 configfile[i]='\0';
	 config_search=0;
	 break; 

      case 'd':	/* set debug level */
         DEBUGC(DBCLASS_CONFIG,"option: set debug level: %s",optarg);
	 cmdline_debuglevel=atoi(optarg);
         log_set_pattern(cmdline_debuglevel);
	 break;

      case 'p':
	 pidfilename = optarg;
	 break;

      default:
         DEBUGC(DBCLASS_CONFIG,"no command line options");
	 break; 
      }
   }
}

/*
 * Init stuff
 */
   INFO(PACKAGE"-"VERSION"-"BUILDSTR" "UNAME" starting up");

   /* read the config file */
   if (read_config(configfile, config_search) == STS_FAILURE) exit(1);

   /* if a debug level > 0 has been given on the commandline use its
      value and not what is in the config file */
   if (cmdline_debuglevel != 0) {
      configuration.debuglevel=cmdline_debuglevel;
   }

   /* set debug level as desired */
   log_set_pattern(configuration.debuglevel);
   log_set_listen_port(configuration.debugport);

   /* change user and group IDs */
   secure_enviroment();

   /* daemonize if requested to */
   if (configuration.daemonize) {
      DEBUGC(DBCLASS_CONFIG,"daemonizing");
      if (fork()!=0) exit(0);
      setsid();
      if (fork()!=0) exit(0);

      log_set_stderr(0);
      INFO("daemonized, pid=%i", getpid());
   }

   /* write PID file of main thread */
   if (pidfilename == NULL) pidfilename = configuration.pid_file;
   if (pidfilename) {
      FILE *pidfile;
      DEBUGC(DBCLASS_CONFIG,"creating PID file [%s]", pidfilename);
      sts=unlink(configuration.pid_file);
      if ((sts==0) ||(errno == ENOENT)) {
         if ((pidfile=fopen(pidfilename, "w"))) {
            fprintf(pidfile,"%i\n",(int)getpid());
            fclose(pidfile);
         } else {
            WARN("couldn't create new PID file: %s", strerror(errno));
         }
      } else {
         WARN("couldn't delete old PID file: %s", strerror(errno));
      }
   }

   /* initialize the RTP proxy */
   sts=rtpproxy_init();
   if (sts != STS_SUCCESS) {
      ERROR("unable to initialize RTP proxy - aborting"); 
      exit(1);
   }

   /* init the oSIP parser */
   parser_init();

   /* listen for incoming messages */
   sts=sipsock_listen();
   if (sts == STS_FAILURE) {
      /* failure to allocate SIP socket... */
      ERROR("unable to bind to SIP listening socket - aborting"); 
      exit(1);
   }

   /* initialize the registration facility */
   register_init();

/*
 * silence the log - if so required...
 */
   log_set_silence(configuration.silence_log);

   INFO(PACKAGE"-"VERSION"-"BUILDSTR" "UNAME" started");

/*
 * Main loop
 */
   while (!exit_program) {

      DEBUGC(DBCLASS_BABBLE,"going into sipsock_wait\n");
      while (sipsock_wait()<=0) {
         /* got no input, here by timeout. do aging */
         register_agemap();

         /* TCP log: check for a connection */
         log_tcp_connect();

         /* dump memory stats if requested to do so */
         if (dmalloc_dump) {
            dmalloc_dump=0;
#ifdef DMALLOC
            INFO("SIGUSR2 - DMALLOC statistics is dumped");
            dmalloc_log_stats();
            dmalloc_log_unfreed();
#else
            INFO("SIGUSR2 - DMALLOC support is not compiled in");
#endif
         }

         if (exit_program) goto exit_prg;
      }

      /* got input, process */
      DEBUGC(DBCLASS_BABBLE,"back from sipsock_wait");

      i=sipsock_read(&buff, sizeof(buff)-1, &ticket.from, &ticket.protocol);
      buff[i]='\0';

      /* evaluate the access lists (IP based filter)*/
      access=accesslist_check(ticket.from);
      if (access == 0) {
         DEBUGC(DBCLASS_ACCESS,"access for this packet was denied");
         continue; /* there are no resources to free */
      }

      /* integrity checks */
      sts=security_check_raw(buff, i);
      if (sts != STS_SUCCESS) {
         DEBUGC(DBCLASS_SIP,"security check (raw) failed");
         continue; /* there are no resources to free */
      }

      /* init sip_msg */
      sts=osip_message_init(&ticket.sipmsg);
      ticket.sipmsg->message=NULL;
      if (sts != 0) {
         ERROR("osip_message_init() failed... this is not good");
	 continue; /* skip, there are no resources to free */
      }

      /*
       * RFC 3261, Section 16.3 step 1
       * Proxy Behavior - Request Validation - Reasonable Syntax
       * (parse the received message)
       */
      sts=osip_message_parse(ticket.sipmsg, buff);
      if (sts != 0) {
         ERROR("osip_message_parse() failed... this is not good");
         DUMP_BUFFER(-1, buff, i);
         goto end_loop; /* skip and free resources */
      }

      /* integrity checks - parsed buffer*/
      sts=security_check_sip(&ticket);
      if (sts != STS_SUCCESS) {
         ERROR("security_check_sip() failed... this is not good");
         DUMP_BUFFER(-1, buff, i);
         goto end_loop; /* skip and free resources */
      }

      /*
       * RFC 3261, Section 16.3 step 2
       * Proxy Behavior - Request Validation - URI scheme
       * (check request URI and refuse with 416 if not understood)
       */
      /* NOT IMPLEMENTED */

      /*
       * RFC 3261, Section 16.3 step 3
       * Proxy Behavior - Request Validation - Max-Forwards check
       * (check Max-Forwards header and refuse with 483 if too many hops)
       */
      {
      osip_header_t *max_forwards;
      int forwards_count = DEFAULT_MAXFWD;

      osip_message_get_max_forwards(ticket.sipmsg, 0, &max_forwards);
      if (max_forwards && max_forwards->hvalue) {
         forwards_count = atoi(max_forwards->hvalue);
      }

      DEBUGC(DBCLASS_PROXY,"checking Max-Forwards (=%i)",forwards_count);
      if (forwards_count <= 0) {
         DEBUGC(DBCLASS_SIP, "Forward count reached 0 -> 483 response");
         sip_gen_response(&ticket, 483 /*Too many hops*/);
         goto end_loop; /* skip and free resources */
      }

      }

      /*
       * RFC 3261, Section 16.3 step 4
       * Proxy Behavior - Request Validation - Loop Detection check
       * (check for loop and return 482 if a loop is detected)
       */
      if (check_vialoop(&ticket) == STS_TRUE) {
         /* make sure we don't end up in endless loop when detecting
          * an loop in an "loop detected" message - brrr */
         if (MSG_IS_RESPONSE(ticket.sipmsg) && 
             MSG_TEST_CODE(ticket.sipmsg, 482)) {
            DEBUGC(DBCLASS_SIP,"loop in loop-response detected, ignoring");
         } else {
            DEBUGC(DBCLASS_SIP,"via loop detected, ignoring request");
            sip_gen_response(&ticket, 482 /*Loop detected*/);
         }
         goto end_loop; /* skip and free resources */
      }

      /*
       * RFC 3261, Section 16.3 step 5
       * Proxy Behavior - Request Validation - Proxy-Require check
       * (check Proxy-Require header and return 420 if unsupported option)
       */
      /* NOT IMPLEMENTED */

      /*
       * RFC 3261, Section 16.5
       * Proxy Behavior - Determining Request Targets
       */
      /* NOT IMPLEMENTED */

      DEBUGC(DBCLASS_SIP,"received SIP type %s:%s",
	     (MSG_IS_REQUEST(ticket.sipmsg))? "REQ" : "RES",
             (MSG_IS_REQUEST(ticket.sipmsg) ?
                ((ticket.sipmsg->sip_method)?
                   ticket.sipmsg->sip_method : "NULL") :
                ((ticket.sipmsg->reason_phrase) ? 
                   ticket.sipmsg->reason_phrase : "NULL")));
              
      /*
       * if an REQ REGISTER, check if it is directed to myself,
       * or am I just the outbound proxy but no registrar.
       * - If I'm the registrar, register & generate answer
       * - If I'm just the outbound proxy, register, rewrite & forward
       */
      if (MSG_IS_REGISTER(ticket.sipmsg) && 
          MSG_IS_REQUEST(ticket.sipmsg)) {
         if (access & ACCESSCTL_REG) {
            osip_uri_t *url;
            struct in_addr addr1, addr2, addr3;
            int dest_port;

            url = osip_message_get_uri(ticket.sipmsg);
            dest_port= (url->port)?atoi(url->port):SIP_PORT;

            if ( (get_ip_by_host(url->host, &addr1) == STS_SUCCESS) &&
                 (get_ip_by_ifname(configuration.inbound_if,&addr2) ==
                  STS_SUCCESS) &&
                 (get_ip_by_ifname(configuration.outbound_if,&addr3) ==
                  STS_SUCCESS)) {

               if ((configuration.sip_listen_port == dest_port) &&
                   ((memcmp(&addr1, &addr2, sizeof(addr1)) == 0) ||
                    (memcmp(&addr1, &addr3, sizeof(addr1)) == 0))) {
                  /* I'm the registrar, send response myself */
                  sts = register_client(&ticket, 0);
                  sts = register_response(&ticket, sts);
               } else {
                  /* I'm just the outbound proxy */
                  DEBUGC(DBCLASS_SIP,"proxying REGISTER request to:%s",
                         url->host);
                  sts = register_client(&ticket, 1);
                  sts = proxy_request(&ticket);
               }
            } else {
               if (MSG_IS_REQUEST(ticket.sipmsg)) {
                  sip_gen_response(&ticket, 408 /*request timeout*/);
               }
            }
	 } else {
            WARN("non-authorized registration attempt from %s",
	         utils_inet_ntoa(ticket.from.sin_addr));
	 }

      /*
       * check if outbound interface is UP.
       * If not, send back error to UA and
       * skip any proxying attempt
       */
      } else if (get_ip_by_ifname(configuration.outbound_if,NULL) !=
                 STS_SUCCESS) {
         DEBUGC(DBCLASS_SIP, "got a %s to proxy, but outbound interface "
                "is down", (MSG_IS_REQUEST(ticket.sipmsg))? "REQ" : "RES");

         if (MSG_IS_REQUEST(ticket.sipmsg))
            sip_gen_response(&ticket, 408 /*request timeout*/);
      
      /*
       * MSG is a request, add current via entry,
       * do a lookup in the URLMAP table and
       * send to the final destination
       */
      } else if (MSG_IS_REQUEST(ticket.sipmsg)) {
         if (access & ACCESSCTL_SIP) {
            sts = proxy_request(&ticket);
	 } else {
            INFO("non-authorized request received from %s",
	         utils_inet_ntoa(ticket.from.sin_addr));
	 }

      /*
       * MSG is a response, remove current via and
       * send to the next VIA in chain
       */
      } else if (MSG_IS_RESPONSE(ticket.sipmsg)) {
         if (access & ACCESSCTL_SIP) {
            sts = proxy_response(&ticket);
	 } else {
            INFO("non-authorized response received from %s",
	         utils_inet_ntoa(ticket.from.sin_addr));
	 }
	 
      /*
       * unsupported message
       */
      } else {
         ERROR("received unsupported SIP type %s %s",
	       (MSG_IS_REQUEST(ticket.sipmsg))? "REQ" : "RES",
	       ticket.sipmsg->sip_method);
      }


/*
 * free the SIP message buffers
 */
      end_loop:
      osip_message_free(ticket.sipmsg);

   } /* while TRUE */
   exit_prg:

   /* dump current known SIP registrations */
   register_shut();
   INFO("properly terminating siproxd");

   /* remove PID file */
   if (pidfilename) {
      DEBUGC(DBCLASS_CONFIG,"deleting PID file [%s]", pidfilename);
      sts=unlink(pidfilename);
      if (sts != 0) {
         WARN("couldn't delete old PID file: %s", strerror(errno));
      }
   }

   /* END */
   return 0;
} /* main */

/*
 * Signal handler
 *
 * this one is called asynchronously whevener a registered
 * signal is applied. Just set a flag and don't do any funny
 * things here.
 */
static void sighandler(int sig) {
   if (sig==SIGTERM) exit_program=1;
   if (sig==SIGINT)  exit_program=1;
   if (sig==SIGUSR2) dmalloc_dump=1;
   return;
}
Esempio n. 6
0
/*
 * binds to SIP UDP socket for listening to incoming packets
 *
 * RETURNS
 *	STS_SUCCESS on success
 *	STS_FAILURE on error
 */
int sipsock_listen (void) {
   struct in_addr ipaddr;
   
   /* start of AU4D00875 by d00107688 to support bind 2008-10-15*/
   struct in_addr wanipaddr;
   /* end of AU4D00875 by d00107688 to support bind 2008-10-15*/

    int i = 0;
   memset(&ipaddr, 0, sizeof(ipaddr));
   /* start of AU4D00875 by d00107688 to support bind 2008-10-15*/
   memset(&wanipaddr, 0, sizeof(wanipaddr));


    if (STS_FAILURE == get_ip_by_ifname(configuration.outbound_if, &wanipaddr))
    {
        ERROR("%s ip: %s", configuration.inbound_if, utils_inet_ntoa(wanipaddr));
        ERROR("can not get the ip , please check it.......");
    }
    else
    {
        g_lsockFlg = 1;
    }
   /* end of AU4D00875 by d00107688 to support bind 2008-10-15*/
   /* start of AU4D00875 by d00107688 to support bind 2008-10-15*/
    if (1 == g_lsockFlg)
    {
   sip_udp_socket = sockbind(ipaddr, configuration.sip_listen_port, 1);
   sip_udp_wan_socket = sockbind(wanipaddr, wanport, 1);
       if (0 == sip_udp_wan_socket)
       {
            for (i = 0; i < 5; i++)
            {
                wanport += (i * 10 + i);
                sip_udp_wan_socket = sockbind(wanipaddr, wanport, 1);
                if (0 == sip_udp_wan_socket)
                {
                    ERROR("bind in port: %d error", wanport);
                    continue;
                }
                else
                {
                    break;
                }
            }
       }
       if ((0 == sip_udp_socket) || (0 == sip_udp_wan_socket)) 
       {
            ERROR("socket bind error");
            return STS_FAILURE; /* failure */
       }
    }
    else
    {
        sip_udp_socket = sockbind(ipaddr, configuration.sip_listen_port, 1);   
   if (sip_udp_socket == 0) return STS_FAILURE; /* failure*/
    }

   INFO("bound to port %i", configuration.sip_listen_port);
   DEBUGC(DBCLASS_NET,"bound socket %i",sip_udp_socket);
   /* end of AU4D00875 by d00107688 to support bind 2008-10-15*/
   return STS_SUCCESS;
}
Esempio n. 7
0
/*
 * sends an UDP datagram to the specified destination
 *
 * RETURNS
 *	STS_SUCCESS on success
 *	STS_FAILURE on error
 *  函数修改说明:
 *      修改人:    l67187
 *      修改目的:  解决代理和绑定时没有默认路由,sip alg无法工作的问题
 *      修改方案:  在报文发送时,bind上网关发送侧的ip地址,使用网关源地址路由
 *      具体修改:  原alg  使用  初始化时创建的 sip_udp_socket,绑定了空地址
 *                 无法再次绑定,修改后,在该函数中不在使用  sip_udp_socket发送报文
 *                 而是重新创建一个socket发送,之后就关闭释放资源
 */
int sipsock_send(struct in_addr addr, int port, int protocol,
                 char *buffer, int size) {
   
   struct sockaddr_in dst_addr;
   struct sockaddr_in stLocalAddr;
   int sock;
   int sts = -1;
   
   /* first time: allocate a socket for sending 
   if (sip_udp_socket == 0) {
      ERROR("SIP socket not allocated");
      return STS_FAILURE;
   }
*/
   if (buffer == NULL) {
      ERROR("sipsock_send got NULL buffer");
      return STS_FAILURE;
   }

   if (protocol != PROTO_UDP) {
      ERROR("sipsock_send: only UDP supported by now");
      return STS_FAILURE;
   }

    if (1 == g_lsockFlg)
    {

        
        dst_addr.sin_family = AF_INET;
        memcpy(&dst_addr.sin_addr.s_addr, &addr, sizeof(struct in_addr));
        dst_addr.sin_port= htons(port);

        if ((1 == IpisInNet(utils_inet_ntoa(addr), g_acBrIpAddr, g_acBrMask))
        || (1 == IpisInNet(utils_inet_ntoa(addr), g_acPPPoEIpAddr, g_acPPPoEMask)))
        {
            
            sts = sendto(sip_udp_socket, buffer, size, 0,
                 (const struct sockaddr *)&dst_addr,
                 (socklen_t)sizeof(dst_addr));
        }
        else  /* wan 侧 */
        {
            // TODO: 这里需要优化,目前PPPoE代理的时候没有默认路由
            // 因此需要进行判断,如果没有默认路由那么就需要使用使用sip_udp_wan_socket
            // 发包,否则一直使用 sip_udp_socket 发包
            // if (没有默认路由)
            if (0 != sip_udp_wan_socket)
            {

                sts = sendto(sip_udp_wan_socket, buffer, size, 0,
                     (const struct sockaddr *)&dst_addr,
                     (socklen_t)sizeof(dst_addr));
            }
            else if (0 == sip_udp_wan_socket)
            {
                sts = sendto(sip_udp_socket, buffer, size, 0,
                     (const struct sockaddr *)&dst_addr,
                     (socklen_t)sizeof(dst_addr));
            }
            else
            {
                ERROR("no proper socket fd to send out");
            }
        }
        
        if (sts == -1) {
           if (errno != ECONNREFUSED) {
              ERROR("sendto() [%s:%i size=%i] call failed: %s",
                    utils_inet_ntoa(addr),
                    port, size, strerror(errno));
              return STS_FAILURE;
           }
           DEBUGC(DBCLASS_BABBLE,"sendto() [%s:%i] call failed: %s",
                  utils_inet_ntoa(addr), port, strerror(errno));
        }
    }
    else
    {
   sock=socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
   if (sock < 0) {
      printsip("Sip: socket() call failed: %s",strerror(errno));
      return STS_FAILURE;
   }

   dst_addr.sin_family = AF_INET;
   memcpy(&dst_addr.sin_addr.s_addr, &addr, sizeof(struct in_addr));
   dst_addr.sin_port= htons(port);

   DEBUGC(DBCLASS_NET,"send UDP packet to %s: %i", utils_inet_ntoa(addr),port);
   
   printsip("Sip:send UDP packet to %s: %i\r\n", utils_inet_ntoa(addr),port);
   DUMP_BUFFER(DBCLASS_NETTRAF, buffer, size);


    /* 本地发送源 */
    bzero(&stLocalAddr, 0);
    /* 目的ip为LAN侧ip */
    if ((1 == IpisInNet(utils_inet_ntoa(addr), g_acBrIpAddr, g_acBrMask))
        || (1 == IpisInNet(utils_inet_ntoa(addr), g_acPPPoEIpAddr, g_acPPPoEMask)))
    {
        get_ip_by_ifname(configuration.inbound_if, &stLocalAddr.sin_addr);
    }
    else
    {
        get_ip_by_ifname(configuration.outbound_if, &stLocalAddr.sin_addr);
    }
/*    
    if (g_lPacketDir == 0)
    {
        get_ip_by_ifname(configuration.outbound_if,&stLocalAddr.sin_addr);
//    stLocalAddr.sin_port = htons(atoi(pszLocalPort));
    }
    else
    {
        get_ip_by_ifname(configuration.inbound_if,&stLocalAddr.sin_addr);
//    stLocalAddr.sin_port = htons(atoi(pszLocalPort));
    }
*/
    stLocalAddr.sin_family = AF_INET;
    
    if (bind(sock, (struct sockaddr *)&stLocalAddr, sizeof(stLocalAddr)) < 0)
    {
    	perror("bind");
    }
    else
    {
        printsip("Sip: bind src ip:[%s]\r\n", inet_ntoa(stLocalAddr.sin_addr));
    }
   
    // if (0 != sip_udp_socket)
        #if 0
    if ((1 == IpisInNet(utils_inet_ntoa(addr), g_acBrIpAddr, g_acBrMask))
        || (1 == IpisInNet(utils_inet_ntoa(addr), g_acPPPoEIpAddr, g_acPPPoEMask)))
        #else
        if (0)
        #endif
    {
        sts = sendto(sock, buffer, size, 0,
             (const struct sockaddr *)&dst_addr,
             (socklen_t)sizeof(dst_addr));
   }
   else if (0 != sip_udp_socket)
   {
       sts = sendto(sip_udp_socket, buffer, size, 0,
                 (const struct sockaddr *)&dst_addr,
                 (socklen_t)sizeof(dst_addr));
   }
   else
   {
        printf("no proper socket found \r\n");
   }
   if (sts == -1) {
      if (errno != ECONNREFUSED) {
         ERROR("sendto() [%s:%i size=%i] call failed: %s",
               utils_inet_ntoa(addr),
               port, size, strerror(errno));
         close(sock);
         return STS_FAILURE;
      }
      DEBUGC(DBCLASS_BABBLE,"sendto() [%s:%i] call failed: %s",
             utils_inet_ntoa(addr), port, strerror(errno));
   }
   close(sock);
    }
   return STS_SUCCESS;
}