Bordeaux is a voice application server for modern IP telephony networks using modern C++ practices along with advances originally made in GNU Bayonne.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

196 lines
6.1 KiB

/*
* Copyright (C) 2020-2021 David Sugar <tychosoft@gmail.com>.
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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, see <http://www.gnu.org/licenses/>.
*/
#include "compiler.hpp"
#include "print.hpp"
#include "strings.hpp"
#include "exosip.hpp"
#include "args.hpp"
#include <thread>
#include <tuple>
#include <unistd.h>
#include <pwd.h>
using namespace std::literals::string_literals;
using namespace std::chrono_literals;
namespace {
exosip::context_t context("bordeaux-utils/" PROJECT_VERSION);
std::string uri = "sip:";
bool ipv6 = false;
bool tls = false;
bool tcp = false;
auto port = 5062;
auto ping_duration = 1000;
args::option opt_ipv6('6', "--ipv6", "enable ipv6");
args::option opt_config('c', "--config", "config file path");
args::option helpflag('h', "--help", "display this list");
args::option opt_info('i', "--info", "display server info");
args::option opt_proxy('p', "--proxy", "proxy route", "uri");
args::option opt_quiet('q', "--quiet", "quiet one time");
args::option opt_srv('s', "--srv", "enable srv lookups");
args::option opt_tcp('t', "--tcp", "enable tcp/tls");
args::option althelp('?', nullptr, nullptr);
auto from()
{
char host[256];
std::string user;
if(gethostname(host, sizeof(host) - 1))
throw bad_arg("no hostname set");
host[sizeof(host) - 1] = 0;
auto pwd = getpwuid(getuid());
if(pwd && pwd->pw_name && pwd->pw_name[0])
user = pwd->pw_name;
else
throw bad_arg("no user set");
endpwent();
return "sip:" + user + "@" + host + ":" + std::to_string(port);
}
void send_ping(const std::string& uri)
{
osip_message_t *msg = nullptr;
exosip::guard_t lock(context);
eXosip_options_build_request(*context, &msg, uri.c_str(), from().c_str(), *opt_proxy);
eXosip_options_send_request(*context, msg);
}
} // end namespace
auto main(int argc, const char **argv) -> int
{
using namespace exosip;
using namespace std::chrono;
int exit_code = 0;
try {
auto count = args::parse(argc, argv);
if(is(helpflag) || is(althelp) || !count) {
args::help({"sip-ping [options] uri"}, {
"Ping remove sip service"
});
return 0;
}
if(count > 1)
throw bad_arg("only use 1 uri");
auto uri_arg = args::list()[0];
ipv6 = *opt_ipv6;
tcp = *opt_tcp;
if(begins_with(uri_arg, "sip:")) {
tls = false;
uri = "sip:";
uri_arg.remove_prefix(4);
}
#ifdef OSIP2_FOUND
else if(begins_with(uri_arg, "sips:")) {
tls = true;
uri = "sips:";
uri_arg.remove_prefix(5);
}
#endif
auto pos = uri_arg.find('@');
auto route = uri;
uri.append(uri_arg);
if(pos != std::string::npos)
route.append(uri_arg.substr(pos));
else
route.append(uri_arg);
if(!is(opt_proxy))
opt_proxy.set(route.c_str());
auto type = tcp ? listen_type::tcp : listen_type::udp;
#ifdef OSIP2_FOUND
if(tls)
type = tcp ? listen_type::tls : listen_type::dtls;
#endif
port = context.find_port(5062, tcp ? IPPROTO_TCP : IPPROTO_UDP);
context.srv_lookup(is(opt_srv));
context.set_family(ipv6 ? family_type::ipv6 : family_type::ipv4);
if(!context.listen("*", type, port))
throw bad_arg("unable to bind to a local port");
//send_ping(uri); was for exosip2 epoll bug (5.2.0-5.2.1)
//std::this_thread::sleep_for(std::chrono::milliseconds(20));
for(;;) {
send_ping(uri);
auto start = steady_clock::now();
auto event = exosip::event_t(context, ping_duration);
auto reply = duration_cast<milliseconds>(steady_clock::now() - start).count();
auto response = event.response();
if(!response) {
exit_code = 3;
if(reply < ping_duration)
++exit_code;
if(is(opt_quiet))
return exit_code;
if(exit_code == 3)
print(std::cerr, "*** sip-ping: {}: unreachable\n", uri);
else {
print(std::cerr, "*** sip-ping: {}: invalid\n", uri);
break;
}
if(is(opt_info))
break;
continue;
}
auto code = response->status_code;
auto reason = response->reason_phrase;
if(code == SIP_OK) {
if(is(opt_info)) {
char *text = nullptr;
size_t size{};
osip_message_to_str(response, &text, &size);
if(text) {
print("{}\n", text);
release(text);
}
return 0;
}
if(is(opt_quiet))
return 0;
print("sip-ping: {}: ok time={}ms\n", uri, reply);
}
else {
exit_code = 2;
if(is(opt_quiet))
return 2;
print(std::cerr, "*** sip-ping: {}: error: {}: {}\n",
uri, code, (reason ? reason : "failure"));
break;
}
std::this_thread::sleep_for(1s);
}
}
catch(const std::exception& e) {
die(-1, "*** sip-ping: {}\n", e.what());
}
catch(...) {
die(-1, "*** sip-ping: unknown error\n");
}
return exit_code;
}