$FreeBSD$ --- modules/nathelper/natping.c.orig +++ modules/nathelper/natping.c @@ -0,0 +1,190 @@ +/* $Id: patch-modules::nathelper::natping.c,v 1.4 2005/04/27 13:35:34 sobomax Exp $ + * + * Copyright (C) 2005 Porta Software Ltd + * + * This file is part of ser, a free SIP server. + * + * ser is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * For a license to use the ser software under conditions + * other than those described here, or to purchase support for this + * software, please contact iptel.org by e-mail at the following addresses: + * info@iptel.org + * + * ser is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "../usrloc/usrloc.h" +#include "../tm/tm_load.h" +#include "../../dprint.h" +#include "../../parser/parse_hostport.h" +#include "../../resolve.h" +#include "nathelper.h" + +int natping_interval = 0; +/* + * If this parameter is set then the natpinger will ping only contacts + * that have the NAT flag set in user location database + */ +int ping_nated_only = 0; + +/* + * Ping method. Any word except NULL is treated as method name. + */ +char *natping_method = NULL; + +static usrloc_api_t ul; +/* TM bind */ +static struct tm_binds tmb; +static int cblen = 0; +static const char sbuf[4] = {0, 0, 0, 0}; + +static void natping(unsigned int ticks, void *param); + +int +natpinger_init(void) +{ + bind_usrloc_t bind_usrloc; + load_tm_f load_tm; + char *p; + + if (natping_interval > 0) { + bind_usrloc = (bind_usrloc_t)find_export("ul_bind_usrloc", 1, 0); + if (!bind_usrloc) { + LOG(L_ERR, "ERROR: nathelper: natpinger_init: Can't find usrloc module\n"); + return -1; + } + + if (bind_usrloc(&ul) < 0) { + return -1; + } + if (natping_method != NULL) { + for (p = natping_method; *p != '\0'; ++p) + *p = toupper(*p); + if (strcmp(natping_method, "NULL") == 0) + natping_method = NULL; + } + if (natping_method != NULL) { + /* import the TM auto-loading function */ + if (!(load_tm = (load_tm_f)find_export("load_tm", NO_SCRIPT, 0))) { + LOG(L_ERR, "ERROR: nathelper: natpinger_init: can't import load_tm\n"); + return -1; + } + /* let the auto-loading function load all TM stuff */ + if (load_tm(&tmb) == -1) + return -1; + } + + register_timer(natping, NULL, natping_interval); + } + + return 0; +} + +static void +natping(unsigned int ticks, void *param) +{ + int rval; + void *buf, *cp; + str c; + struct sip_uri curi; + union sockaddr_union to; + struct hostent* he; + struct socket_info* send_sock; + char t; + str p_method, p_from; + + buf = NULL; + if (cblen > 0) { + buf = pkg_malloc(cblen); + if (buf == NULL) { + LOG(L_ERR, "ERROR: nathelper::natping: out of memory\n"); + return; + } + } + rval = ul.get_all_ucontacts(buf, cblen, (ping_nated_only ? FL_NAT : 0)); + if (rval > 0) { + if (buf != NULL) + pkg_free(buf); + cblen = rval * 2; + buf = pkg_malloc(cblen); + if (buf == NULL) { + LOG(L_ERR, "ERROR: nathelper::natping: out of memory\n"); + return; + } + rval = ul.get_all_ucontacts(buf, cblen, (ping_nated_only ? FL_NAT : 0)); + if (rval != 0) { + pkg_free(buf); + return; + } + } + + if (buf == NULL) + return; + + cp = buf; + while (1) { + memcpy(&(c.len), cp, sizeof(c.len)); + if (c.len == 0) + break; + c.s = (char*)cp + sizeof(c.len); + cp = (char*)cp + sizeof(c.len) + c.len; + if (parse_uri(c.s, c.len, &curi) < 0) { + LOG(L_ERR, "ERROR: nathelper::natping: can't parse contact uri\n"); + continue; + } + if (curi.proto != PROTO_UDP && curi.proto != PROTO_NONE) + continue; + + if (natping_method != NULL) { + p_method.s = natping_method; + p_method.len = strlen(p_method.s); + p_from.s = "sip:registrar"; /* XXX */ + p_from.len = strlen(p_from.s); + if (tmb.t_request(&p_method, &c, &c, &p_from, + NULL, NULL, NULL, NULL) == -1) + { + LOG(L_ERR, "nathelper::natping(): request() failed\n"); + } + } else { + if (curi.maddr_val.len != 0) { + t = curi.maddr_val.s[curi.maddr_val.len]; + curi.maddr_val.s[curi.maddr_val.len] = '\0'; + parse_hostport(curi.maddr_val.s, &curi.host, &curi.port_no); + curi.maddr_val.s[curi.maddr_val.len] = t; + if (curi.host.len <= 0) { + LOG(L_ERR, "ERROR: nathelper::natping: invalid maddr in contact uri\n"); + continue; + } + } + + if (curi.port_no == 0) + curi.port_no = SIP_PORT; + he = sip_resolvehost(&curi.host, &curi.port_no, PROTO_UDP); + if (he == NULL){ + LOG(L_ERR, "ERROR: nathelper::natping: can't resolve host\n"); + continue; + } + hostent2su(&to, he, 0, curi.port_no); + send_sock=force_socket ? force_socket : + get_send_socket(0, &to, PROTO_UDP); + if (send_sock == NULL) { + LOG(L_ERR, "ERROR: nathelper::natping: can't get sending socket\n"); + continue; + } + udp_send(send_sock, (char *)sbuf, sizeof(sbuf), &to); + } + } + pkg_free(buf); +}