agent.cc 27.1 KB
Newer Older
Simon Morlat's avatar
Simon Morlat committed
1
/*
Yann Diorcet's avatar
Yann Diorcet committed
2 3
 Flexisip, a flexible SIP proxy server with media capabilities.
 Copyright (C) 2010  Belledonne Communications SARL.
Simon Morlat's avatar
Simon Morlat committed
4

Yann Diorcet's avatar
Yann Diorcet committed
5 6 7 8
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as
 published by the Free Software Foundation, either version 3 of the
 License, or (at your option) any later version.
Simon Morlat's avatar
Simon Morlat committed
9

Yann Diorcet's avatar
Yann Diorcet committed
10 11 12 13
 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 Affero General Public License for more details.
Simon Morlat's avatar
Simon Morlat committed
14

Yann Diorcet's avatar
Yann Diorcet committed
15 16 17
 You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
Simon Morlat's avatar
Simon Morlat committed
18

19
#if defined(HAVE_CONFIG_H) && !defined(FLEXISIP_INCLUDED)
jehan's avatar
jehan committed
20
#include "flexisip-config.h"
21
#define FLEXISIP_INCLUDED
jehan's avatar
jehan committed
22
#endif
23
#include "agent.hh"
24
#include "module.hh"
25

26 27 28
#include "log/logmanager.hh"
#include "sipattrextractor.hh"

29
#include "etchosts.hh"
30
#include <algorithm>
jehan's avatar
jehan committed
31
#include <sstream>
32
#include <sofia-sip/tport_tag.h>
33
#include <sofia-sip/su_tagarg.h>
34
#include <sofia-sip/sip.h>
35
#include <sofia-sip/su_md5.h>
36
#include <sofia-sip/tport.h>
37

38 39 40 41
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

42 43 44
#include <net/if.h>
#include <ifaddrs.h>

45 46
#define IPADDR_SIZE 64

Yann Diorcet's avatar
Yann Diorcet committed
47
using namespace ::std;
48

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
static StatCounter64 *createCounter(GenericStruct *global, string keyprefix, string helpprefix, string value) {
	return global->createStat(keyprefix+value, helpprefix + value +".");
}
void Agent::onDeclare(GenericStruct *root) {
	GenericStruct *global=root->get<GenericStruct>("global");
	string key="count-incoming-request-";
	string help="Number of incoming requests with method name ";
	mCountIncomingRegister=createCounter(global,key, help, "register");
	mCountIncomingInvite=createCounter(global,key, help, "invite");
	mCountIncomingAck=createCounter(global,key, help, "ack");
	mCountIncomingInfo=createCounter(global,key, help, "info");
	mCountIncomingBye=createCounter(global,key, help, "bye");
	mCountIncomingCancel=createCounter(global,key, help, "cancel");
	mCountIncomingMessage=createCounter(global,key, help, "message");
	mCountIncomingDecline=createCounter(global,key, help, "decline");
	mCountIncomingOptions=createCounter(global,key, help, "options");
	mCountIncomingReqUnknown=createCounter(global,key, help, "unknown");

	key="count-incoming-response-";
	help= "Number of incoming response with status ";
	mCountIncoming100=createCounter(global,key, help, "100");
	mCountIncoming101=createCounter(global,key, help, "101");
	mCountIncoming180=createCounter(global,key, help, "180");
	mCountIncoming200=createCounter(global,key, help, "200");
	mCountIncoming202=createCounter(global,key, help, "202");
	mCountIncoming401=createCounter(global,key, help, "401");
	mCountIncoming404=createCounter(global,key, help, "404");
	mCountIncoming407=createCounter(global,key, help, "407");
77
	mCountIncoming408=createCounter(global,key, help, "408");
78
	mCountIncoming486=createCounter(global,key, help, "486");
79
	mCountIncoming487=createCounter(global,key, help, "487");
80 81 82 83 84 85 86 87 88 89 90 91 92 93
	mCountIncoming488=createCounter(global,key, help, "488");
	mCountIncoming603=createCounter(global,key, help, "603");
	mCountIncomingResUnknown=createCounter(global,key, help, "unknown");

	key="count-reply-";
	help="Number of replied ";
	mCountReply100=createCounter(global,key, help, "100");
	mCountReply101=createCounter(global,key, help, "101");
	mCountReply180=createCounter(global,key, help, "180");
	mCountReply200=createCounter(global,key, help, "200");
	mCountReply202=createCounter(global,key, help, "202");
	mCountReply401=createCounter(global,key, help, "401");
	mCountReply404=createCounter(global,key, help, "404");
	mCountReply407=createCounter(global,key, help, "407");
94
	mCountReply408=createCounter(global,key, help, "408"); // request timeout
95
	mCountReply486=createCounter(global,key, help, "486");
96
	mCountReply487=createCounter(global,key, help, "487"); // Request canceled
97 98
	mCountReply488=createCounter(global,key, help, "488");
	mCountReplyResUnknown=createCounter(global,key, help, "unknown");
99
	mLogWriter=NULL;
100 101
}

102 103 104 105 106 107 108 109 110 111 112
void Agent::startLogWriter(){
	GenericStruct *cr=GenericManager::get()->getRoot();
	bool enabled=cr->get<GenericStruct>("global")->get<ConfigBoolean>("enable-event-logs")->read();
	string logdir=cr->get<GenericStruct>("global")->get<ConfigString>("event-logs-dir")->read();
	if (enabled){
		FilesystemEventLogWriter *lw=new FilesystemEventLogWriter(logdir);
		if (!lw->isReady()){
			delete lw;
		}else mLogWriter=lw;
	}
}
113

114 115 116 117 118 119
static string absolutePath(const string &currdir, const string &file) {
	if (file.empty()) return file;
	if (file.at(0) == '/') return file;
	return currdir + "/" + file;
}

120
void Agent::start(const char *transport_override){
121 122 123 124 125 126 127 128 129 130
	char cCurrDir[FILENAME_MAX];
	if (!getcwd(cCurrDir, sizeof(cCurrDir))) {
		LOGA("Could not get current file path");
	}
	string currDir = cCurrDir;

	GenericStruct *global=GenericManager::get()->getRoot()->get<GenericStruct>("global");
		list<string> transports = global->get<ConfigStringList>("transports")->read();
	//sofia needs a value in millseconds.
	int tports_idle_timeout = 1000 * global->get<ConfigInt>("idle-timeout")->read();
131
	bool mainPeerCert = global->get<ConfigBoolean>("require-peer-certificate")->read();
132
	string mainTlsCertsDir = global->get<ConfigString>("tls-certificates-dir")->read();
133
	int t1x64=global->get<ConfigInt>("transaction-timeout")->read();
134
	mainTlsCertsDir = absolutePath(currDir, mainTlsCertsDir);
135

136 137
	SLOGD << "Main tls certs dir : " << mainTlsCertsDir;

138 139
	nta_agent_set_params(mAgent,NTATAG_SIP_T1X64(t1x64),TAG_END());
	
140 141 142 143 144 145 146 147 148 149 150 151 152
	if (transport_override){
		transports=ConfigStringList::parse(transport_override);
	}

	for(auto it=transports.begin();it!=transports.end();++it){
		const string &uri=(*it);
		url_t *url;
		int err;
		su_home_t home;
		su_home_init(&home);
		url=url_make(&home,uri.c_str());
		LOGD("Enabling transport %s",uri.c_str());
		if (uri.find("sips")==0){
153 154 155 156
			string keys;
			if (url_has_param(url,"tls-certificates-dir")) {
				char keys_path[512];
				url_param(url->url_params,"tls-certificates-dir",keys_path,sizeof(keys_path));
157
				keys=keys_path, keys = absolutePath(currDir, keys);
158
			} else {
159
				 keys = mainTlsCertsDir;
160
			}
161 162 163 164 165 166 167 168 169 170 171
			bool peerCert;
			if (url_has_param(url,"require-peer-certificate")) {
				char require_value[50];
				url_param(url->url_params,"require-peer-certificate", require_value, sizeof(require_value));
				string reqval = require_value;
				peerCert = reqval == "1" || reqval == "true";
				if (!peerCert && reqval != "0" && reqval != "false")
					LOGA("Bad require-peer-certificate value: %s", require_value);
			} else {
				peerCert = mainPeerCert;
			}
172 173 174 175 176 177 178
			err=nta_agent_add_tport(mAgent,
									(const url_string_t*) url,
									TPTAG_CERTIFICATE(keys.c_str()),
									TPTAG_TLS_VERIFY_PEER(peerCert),  
									NTATAG_TLS_RPORT(1),
									TPTAG_IDLE(tports_idle_timeout),
									TAG_END());
179
		}else{
180 181 182 183 184
			err=nta_agent_add_tport(mAgent,
									(const url_string_t*) url,
									NTATAG_CLIENT_RPORT(1),
									TPTAG_IDLE(tports_idle_timeout),
									TAG_END());
185 186 187 188 189 190
		}
		if (err==-1){
			LOGE("Could not enable transport %s: %s",uri.c_str(),strerror(errno));
		}
		su_home_deinit(&home);
	}
191 192
	
	tport_t *primaries=tport_primaries(nta_agent_tports(mAgent));
193
	if (primaries==NULL) LOGF("No sip transport defined.");
194 195
	su_md5_t ctx;
	su_md5_init(&ctx);
196

197 198 199 200 201 202 203
	/*
	 * Iterate on all the transports enabled or implicitely configured (case of 'sip:*') in order to guess useful information from an empiric manner:
	 * mPublicIpV4/mPublicIpV6 is the public IP of the proxy, assuming there's only one.
	 * mPreferredRouteV4/mPreferredRouteV6 is a private interface of the proxy that can be used for inter flexisip nodes SIP communication.
	 * mRtpBindIp/mRtpBindIp6 is a local address to bind rtp ports. It is taken from maddr parameter of the public transport of the proxy.
	 * This algo is really empiric and aims at satisfy most common needs but cannot satisfy all of them.
	**/
204 205 206 207 208
	LOGD("Agent 's primaries are:");
	for(tport_t *tport=primaries;tport!=NULL;tport=tport_next(tport)){
		const tp_name_t *name;
		char url[512];
		name=tport_name(tport);
209
		snprintf(url,sizeof(url),"sip:%s:%s;transport=%s;maddr=%s",name->tpn_canon,name->tpn_port,name->tpn_proto,name->tpn_host);
210 211
		su_md5_strupdate(&ctx,url);
		LOGD("\t%s",url);
212
		bool isIpv6=strchr(name->tpn_host, ':') != NULL;
213
		if (strcmp(name->tpn_canon,name->tpn_host)!=0) {
Simon Morlat's avatar
Simon Morlat committed
214 215 216
			// The public and bind values are different
			// which is the case of transport with sip:public;maddr=bind
			// where public is the hostname or ip address publicly announced
217 218 219 220
			// and maddr the real ip we listen on.
			// Useful for a scenario where the flexisip is behind a router.
			if (isIpv6 && mPublicIpV6.empty()) {
				mPublicIpV6=name->tpn_canon;
221
				mRtpBindIp6=name->tpn_host;
Simon Morlat's avatar
Simon Morlat committed
222
				//LOGD("\tIpv6 public ip is %s", mPublicIpV6.c_str());
223 224
			} else if (!isIpv6 && mPublicIpV4.empty()) {
				mPublicIpV4=name->tpn_canon;
225
				mRtpBindIp=name->tpn_host;
Simon Morlat's avatar
Simon Morlat committed
226
				//LOGD("\tIpv4 public ip %s", mPublicIpV4.c_str());
227
			}
228
		}
229 230 231 232 233 234 235 236 237
		url_t **preferred=isIpv6?&mPreferredRouteV6:&mPreferredRouteV4;
		if (*preferred == NULL) {
			tp_name_t tp_priv_name=*name;
			tp_priv_name.tpn_canon=tp_priv_name.tpn_host;
			*preferred=ModuleToolbox::urlFromTportName(&mHome,&tp_priv_name);
			//char prefUrl[266];
			//url_e(prefUrl,sizeof(prefUrl),*preferred);
			//LOGD("\tDetected %s preferred route to %s", isIpv6 ? "ipv6":"ipv4", prefUrl);
		}
238 239
	}
	
240 241
	if (mPublicIpV4.empty() && mPreferredRouteV4) mPublicIpV4=mPreferredRouteV4->url_host;
	if (mPublicIpV6.empty() && mPreferredRouteV6) mPublicIpV6=mPreferredRouteV6->url_host;
242
	
243
	if (mRtpBindIp.empty() && mPreferredRouteV4) {
244 245
		mRtpBindIp=mPreferredRouteV4->url_host;
	}
246
	if (mRtpBindIp6.empty() && mPreferredRouteV6) {
247 248 249
		mRtpBindIp6=mPreferredRouteV6->url_host;
	}
	
Simon Morlat's avatar
Simon Morlat committed
250 251 252
	if (mRtpBindIp.empty()) mRtpBindIp="0.0.0.0";
	if (mRtpBindIp6.empty()) mRtpBindIp6="::0";
	
253 254 255 256 257 258 259
	char digest[(SU_MD5_DIGEST_SIZE*2)+1];
	su_md5_hexdigest(&ctx,digest);
	su_md5_deinit(&ctx);
	digest[16]='\0';//keep half of the digest, should be enough
	// compute a network wide unique id
	mUniqueId = digest;
	
260 261
	LOGD("Agent public hostname/ip: v4:%s v6:%s",mPublicIpV4.c_str(), mPublicIpV6.c_str());
	LOGD("Agent's _default_ RTP bind ip address: v4:%s v6:%s",mRtpBindIp.c_str(),mRtpBindIp6.c_str());
262
	
263 264 265 266
	char prefUrl4[256]={0};
	char prefUrl6[256]={0};
	if (mPreferredRouteV4) url_e(prefUrl4,sizeof(prefUrl4),mPreferredRouteV4);
	if (mPreferredRouteV6) url_e(prefUrl6,sizeof(prefUrl6),mPreferredRouteV6);
267
	LOGD("Agent's preferred IP for internal routing: v4: %s v6:%s",prefUrl4,prefUrl6);
268
	startLogWriter();
269 270
}

271
Agent::Agent(su_root_t* root):mBaseConfigListener(NULL), mTerminating(false){
272
	mHttpEngine = nth_engine_create(root, NTHTAG_ERROR_MSG(0), TAG_END());
273 274
	GenericStruct *cr = GenericManager::get()->getRoot();
	
275
	EtcHostsResolver::get();
276

277
	mModules.push_back(ModuleFactory::get()->createModuleInstance(this, "SanityChecker"));
278
	mModules.push_back(ModuleFactory::get()->createModuleInstance(this, "GarbageIn"));
279 280
	mModules.push_back(ModuleFactory::get()->createModuleInstance(this, "NatHelper"));
	mModules.push_back(ModuleFactory::get()->createModuleInstance(this, "Authentication"));
281 282 283
#ifdef HAVE_DATEHANDLER
	mModules.push_back(ModuleFactory::get()->createModuleInstance(this, "DateHandler"));
#endif
284 285
	mModules.push_back(ModuleFactory::get()->createModuleInstance(this, "GatewayAdapter"));
	mModules.push_back(ModuleFactory::get()->createModuleInstance(this, "Registrar"));
286
	mModules.push_back(ModuleFactory::get()->createModuleInstance(this, "ContactRouteInserter"));
287
	mModules.push_back(ModuleFactory::get()->createModuleInstance(this, "Router"));
288 289 290
#ifdef ENABLE_PUSHNOTIFICATION
	mModules.push_back(ModuleFactory::get()->createModuleInstance(this, "PushNotification"));
#endif
291 292
	mModules.push_back(ModuleFactory::get()->createModuleInstance(this, "LoadBalancer"));
	mModules.push_back(ModuleFactory::get()->createModuleInstance(this, "MediaRelay"));
293
#ifdef ENABLE_TRANSCODER
294 295 296 297
	const auto &overrideMap=GenericManager::get()->getOverrideMap();
	if (overrideMap.find("notrans") == overrideMap.end()) {
		mModules.push_back(ModuleFactory::get()->createModuleInstance(this,"Transcoder"));
	}
298
#endif
Yann Diorcet's avatar
Yann Diorcet committed
299
	mModules.push_back(ModuleFactory::get()->createModuleInstance(this, "Forward"));
300

Yann Diorcet's avatar
Yann Diorcet committed
301 302 303
	mServerString = "Flexisip/"
	VERSION
	" (sofia-sip-nta/" NTA_VERSION ")";
304

Yann Diorcet's avatar
Yann Diorcet committed
305
	for_each(mModules.begin(), mModules.end(), bind2nd(mem_fun(&Module::declare), cr));
306
	onDeclare(cr);
307

308 309 310 311 312 313 314 315 316 317 318
	struct ifaddrs *net_addrs;
	int err = getifaddrs(&net_addrs);
	if (err == 0) {
		struct ifaddrs * ifa = net_addrs;
		while (ifa != NULL) {
			if (ifa->ifa_netmask != NULL && ifa->ifa_addr != NULL) {
				LOGD("New network: %s", Network::print(ifa).c_str());
				mNetworks.push_front(Network(ifa));
			}
			ifa = ifa->ifa_next;
		}
319
		freeifaddrs(net_addrs);
320 321 322
	} else {
		LOGE("Can't find interface addresses: %s", strerror(err));
	}
323
	mRoot = root;
Simon Morlat's avatar
Simon Morlat committed
324
	mAgent = nta_agent_create(root, (url_string_t*) -1, &Agent::messageCallback, (nta_agent_magic_t*) this, NTATAG_UDP_MTU(1460), TAG_END());
325
	su_home_init(&mHome);
326 327
	mPreferredRouteV4=NULL;
	mPreferredRouteV6=NULL;
328 329
}

Yann Diorcet's avatar
Yann Diorcet committed
330
Agent::~Agent() {
331
	mTerminating=true;
Yann Diorcet's avatar
Yann Diorcet committed
332
	for_each(mModules.begin(), mModules.end(), delete_functor<Module>());
333 334
	if (mAgent)	nta_agent_destroy(mAgent);
	if (mHttpEngine) nth_engine_destroy(mHttpEngine);
335
	su_home_deinit(&mHome);
336 337
}

Yann Diorcet's avatar
Yann Diorcet committed
338
const char *Agent::getServerString() const {
339 340 341
	return mServerString.c_str();
}

342 343
std::string Agent::getPreferredRoute()const{
	char prefUrl[266];
344
	url_e(prefUrl,sizeof(prefUrl),mPreferredRouteV4);
345 346 347
	return string(prefUrl);
}

348 349 350 351 352 353 354 355 356 357 358 359 360
bool Agent::doOnConfigStateChanged(const ConfigValue &conf, ConfigState state) {
	LOGD("Configuration of agent changed for key %s to %s",
			conf.getName().c_str(), conf.get().c_str());

	if (conf.getName() == "aliases" && state == ConfigState::Commited) {
		mAliases=((ConfigStringList*)(&conf))->read();
		LOGD("Global aliases updated");
		return true;
	}

	return mBaseConfigListener->onConfigStateChanged(conf, state);
}

361 362
void Agent::loadConfig(GenericManager *cm) {
	cm->loadStrict(); //now that each module has declared its settings, we need to reload from the config file
363 364 365 366
	if (!mBaseConfigListener) {
		mBaseConfigListener=cm->getGlobal()->getConfigListener();
	}
	cm->getRoot()->get<GenericStruct>("global")->setConfigListener(this);
367
	mAliases = cm->getGlobal()->get<ConfigStringList>("aliases")->read();
Simon Morlat's avatar
Simon Morlat committed
368
	LOGD("List of host aliases:");
Yann Diorcet's avatar
Yann Diorcet committed
369 370
	for (list<string>::iterator it = mAliases.begin(); it != mAliases.end(); ++it) {
		LOGD("%s", (*it).c_str());
Simon Morlat's avatar
Simon Morlat committed
371
	}
372
	list<Module*>::iterator it;
Guillaume Beraudo's avatar
Guillaume Beraudo committed
373 374 375 376
	for (it = mModules.begin(); it != mModules.end(); ++it) {
		// Check in all cases, even if not enabled,
		// to allow safe dynamic activation of the module
		(*it)->checkConfig();
377
		(*it)->load();
Guillaume Beraudo's avatar
Guillaume Beraudo committed
378
	}
Simon Morlat's avatar
Simon Morlat committed
379 380
}

381

382
std::pair<std::string,std::string> Agent::getPreferredIp(const std::string &destination) const {
383
	int err;
384 385 386 387
	struct addrinfo hints;
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_flags = AI_NUMERICHOST;
388

389
	struct addrinfo *result;
390
	err = getaddrinfo(destination.c_str(), NULL, &hints, &result);
391 392 393 394
	if (err == 0) {
		for (auto it = mNetworks.begin(); it != mNetworks.end(); ++it) {
			if (it->isInNetwork(result->ai_addr)) {
				freeaddrinfo(result);
395
				return make_pair(it->getIP(),it->getIP());
396 397
			}
		}
398 399 400
		freeaddrinfo(result);
	} else {
		LOGE("getaddrinfo error: %s", strerror(errno));
401
	}
402
	return strchr(destination.c_str(),':')==NULL ? make_pair(getPublicIp(),getRtpBindIp()) : make_pair(getPublicIp(true),getRtpBindIp(true));
403 404
}

405
Agent::Network::Network(const Network &net): mIP(net.mIP) {
406 407
	memcpy(&mPrefix, &net.mPrefix, sizeof(mPrefix));
	memcpy(&mMask, &net.mMask, sizeof(mMask));
408 409
}

410
Agent::Network::Network(const struct ifaddrs *ifaddr) {
411
	int err = 0;
412
	char ipAddress[IPADDR_SIZE];
413 414
	memset(&mPrefix, 0, sizeof(mPrefix));
	memset(&mMask, 0, sizeof(mMask));
415
	if (ifaddr->ifa_addr->sa_family == AF_INET) {
416 417 418 419 420 421 422 423 424 425
		typedef struct sockaddr_in sockt;
		sockt *if_addr = (sockt *) ifaddr->ifa_addr;
		sockt *if_mask = (sockt *) ifaddr->ifa_netmask;
		sockt *prefix = (sockt *) &mPrefix;
		sockt *mask = (sockt *) &mMask;

		mPrefix.ss_family = AF_INET;
		prefix->sin_addr.s_addr = if_addr->sin_addr.s_addr & if_mask->sin_addr.s_addr;
		mask->sin_addr.s_addr = if_mask->sin_addr.s_addr; // 1 chunk of 32 bits
		err = getnameinfo(ifaddr->ifa_addr, sizeof(sockt), ipAddress, IPADDR_SIZE, NULL, 0, NI_NUMERICHOST);
426
	} else if (ifaddr->ifa_addr->sa_family == AF_INET6) {
427 428 429 430 431 432 433 434 435 436
		typedef struct sockaddr_in6 sockt;
		sockt *if_addr = (sockt *) ifaddr->ifa_addr;
		sockt *if_mask = (sockt *) ifaddr->ifa_netmask;
		sockt *prefix = (sockt *) &mPrefix;
		sockt *mask = (sockt *) &mMask;

		mPrefix.ss_family = AF_INET6;
		for (int i = 0; i < 8; ++i) { // 8 chunks of 8 bits
			prefix->sin6_addr.s6_addr[i] = if_addr->sin6_addr.s6_addr[i] & if_mask->sin6_addr.s6_addr[i];
			mask->sin6_addr.s6_addr[i] = if_mask->sin6_addr.s6_addr[i];
437
		}
438
		err = getnameinfo(ifaddr->ifa_addr, sizeof(sockt), ipAddress, IPADDR_SIZE, NULL, 0, NI_NUMERICHOST);
439 440 441 442 443 444 445 446 447 448 449 450 451 452
	}
	if (err == 0) {
		mIP = string(ipAddress);
	} else {
		LOGE("getnameinfo error: %s", strerror(errno));
	}

}

const string Agent::Network::getIP() const {
	return mIP;
}

bool Agent::Network::isInNetwork(const struct sockaddr *addr) const {
453
	if (addr->sa_family != mPrefix.ss_family) {
454 455
		return false;
	}
456

457
	if (addr->sa_family == AF_INET) {
458 459 460 461 462 463 464
		typedef struct sockaddr_in sockt;
		sockt *prefix = (sockt *) &mPrefix;
		sockt *mask = (sockt *) &mMask;
		sockt *if_addr = (sockt *) addr;

		uint32_t test = if_addr->sin_addr.s_addr & mask->sin_addr.s_addr;
		return test == prefix->sin_addr.s_addr;
465
	} else if (addr->sa_family == AF_INET6) {
466 467 468 469 470 471 472 473
		typedef struct sockaddr_in6 sockt;
		sockt *prefix = (sockt *) &mPrefix;
		sockt *mask = (sockt *) &mMask;
		sockt *if_addr = (sockt *) addr;

		for (int i = 0; i < 8; ++i) {
			uint8_t test = if_addr->sin6_addr.s6_addr[i] & mask->sin6_addr.s6_addr[i];
			if (test != prefix->sin6_addr.s6_addr[i])
474 475
				return false;
		}
476 477 478
		return true;
	} else {
		LOGF("Network::isInNetwork: cannot happen");
479 480 481 482 483 484
	}
}

string Agent::Network::print(const struct ifaddrs *ifaddr) {
	stringstream ss;
	int err;
485
	int size = (ifaddr->ifa_addr->sa_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
486 487 488
	char result[IPADDR_SIZE];
	ss << "Name: " << ifaddr->ifa_name;

489
	err = getnameinfo(ifaddr->ifa_addr, size, result, IPADDR_SIZE, NULL, 0, NI_NUMERICHOST);
490 491 492 493 494
	if (err != 0) {
		ss << "\tAddress: " << "(Error)";
	} else {
		ss << "\tAddress: " << result;
	}
495
	err = getnameinfo(ifaddr->ifa_netmask, size, result, IPADDR_SIZE, NULL, 0, NI_NUMERICHOST);
496 497 498 499 500 501 502
	if (err != 0) {
		ss << "\tMask: " << "(Error)";
	} else {
		ss << "\tMask: " << result;
	}

	return ss.str();
Simon Morlat's avatar
Simon Morlat committed
503 504
}

Yann Diorcet's avatar
Yann Diorcet committed
505
int Agent::countUsInVia(sip_via_t *via) const {
506
	int count = 0;
Yann Diorcet's avatar
Yann Diorcet committed
507 508 509
	for (sip_via_t *v = via; v != NULL; v = v->v_next) {
		if (isUs(v->v_host, v->v_port, true))
			++count;
510 511 512 513 514
	}

	return count;
}

Yann Diorcet's avatar
Yann Diorcet committed
515 516
bool Agent::isUs(const char *host, const char *port, bool check_aliases) const {
	char *tmp = NULL;
517
	int end;
518
	tport_t *tport=tport_primaries(nta_agent_tports(mAgent));
519
	
520
	//skip possibly trailing '.' at the end of host
Yann Diorcet's avatar
Yann Diorcet committed
521 522 523 524 525
	if (host[end = (strlen(host) - 1)] == '.') {
		tmp = (char*) alloca(end+1);
		memcpy(tmp, host, end);
		tmp[end] = '\0';
		host = tmp;
526
	}
527
	const char *matched_port=port;
528 529
	for(;tport!=NULL;tport=tport_next(tport)){
		const tp_name_t *tn=tport_name(tport);
530
		if (port==NULL){
531
			if (strcmp(tn->tpn_proto,"tls")==0)
532 533 534
				matched_port="5061";
			else matched_port="5060";
		}
535 536
		if (strcmp(matched_port,tn->tpn_port)==0){
			if (strcmp(host,tn->tpn_canon)==0)
Yann Diorcet's avatar
Yann Diorcet committed
537
				return true;
538 539 540 541 542 543 544
			if (check_aliases) {
				list<string>::const_iterator it;
				for (it = mAliases.begin(); it != mAliases.end(); ++it) {
					if (strcasecmp(host, (*it).c_str()) == 0)
						return true;
				}
			}
545
		}
Simon Morlat's avatar
Simon Morlat committed
546 547
	}
	return false;
Simon Morlat's avatar
Simon Morlat committed
548 549
}

Yann Diorcet's avatar
Yann Diorcet committed
550
sip_via_t *Agent::getNextVia(sip_t *response) {
Simon Morlat's avatar
Simon Morlat committed
551
	sip_via_t *via;
Yann Diorcet's avatar
Yann Diorcet committed
552
	for (via = response->sip_via; via != NULL; via = via->v_next) {
553
		if (!isUs(via->v_host, via->v_port, false))
Simon Morlat's avatar
Simon Morlat committed
554 555 556 557 558
			return via;
	}
	return NULL;
}

559 560 561
/**
 * Takes care of an eventual maddr parameter.
 */
Yann Diorcet's avatar
Yann Diorcet committed
562
bool Agent::isUs(const url_t *url, bool check_aliases) const {
563 564 565 566 567 568
	char maddr[50];
	if (url_param(url->url_params, "maddr", maddr, sizeof(maddr))) {
		return isUs(maddr, url->url_port, check_aliases);
	} else {
		return isUs(url->url_host, url->url_port, check_aliases);
	}
Yann Diorcet's avatar
Yann Diorcet committed
569 570
}

571 572 573
void Agent::logEvent(const shared_ptr<SipEvent> &ev){
	if (mLogWriter){
		shared_ptr<EventLog> evlog;
574
		if ((evlog=ev->getEventLog<EventLog>())){
575 576 577 578 579
			if (evlog->isCompleted()) mLogWriter->write(evlog);
		}
	}
}

580 581 582 583 584 585 586 587 588 589 590 591 592 593
struct ModuleHasName {
	ModuleHasName(const string &ref) :
	match(ref) {
	}
	bool operator()(Module *module) {
		return module->getModuleName() == match;
	}
	const string &match;
};
Module *Agent::findModule(const string &modname) const {
	auto it=find_if(mModules.begin(), mModules.end(), ModuleHasName(modname));
	return (it != mModules.end()) ? *it : NULL;
}

594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
template <typename SipEventT>
inline void Agent::doSendEvent
(shared_ptr<SipEventT> ev, const list<Module *>::iterator &begin, const list<Module *>::iterator &end) {
	#define LOG_SCOPED_EV_THREAD(ssargs, key) LOG_SCOPED_THREAD(key, ssargs->getOrEmpty(key));
	
	auto ssargs=ev->getMsgSip()->getSipAttr();
	LOG_SCOPED_EV_THREAD(ssargs, "from.uri.user");
	LOG_SCOPED_EV_THREAD(ssargs, "from.uri.domain");
	LOG_SCOPED_EV_THREAD(ssargs, "to.uri.user");
	LOG_SCOPED_EV_THREAD(ssargs, "to.uri.domain");
	LOG_SCOPED_EV_THREAD(ssargs, "method_or_status");
	LOG_SCOPED_EV_THREAD(ssargs, "callid");
	

	for (auto it = begin; it != end; ++it) {
		ev->mCurrModule = (*it);
		(*it)->process(ev);
		if (ev->isTerminated() || ev->isSuspended())
			break;
	}
	if (!ev->isTerminated() && !ev->isSuspended()) {
		LOGA("Event not handled");
	}	
}


620
void Agent::sendRequestEvent(shared_ptr<RequestSipEvent> ev) {
621
	sip_t *sip=ev->getMsgSip()->mSip;
622 623 624 625 626 627
	const sip_request_t *req=sip->sip_request;
	const url_t *from= sip->sip_from->a_url;
	SLOGD << "Receiving new Request SIP message "
		<< req->rq_method_name
		<< " from " << from->url_user << "@" << from->url_host << " :"
		<< "\n" << *ev->getMsgSip();
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
	switch (req->rq_method) {
	case sip_method_register:
		++*mCountIncomingRegister;
		break;
	case sip_method_invite:
		++*mCountIncomingInvite;
		break;
	case sip_method_ack:
		++*mCountIncomingAck;
		break;
	case sip_method_info:
		++*mCountIncomingInfo;
		break;
	case sip_method_cancel:
		++*mCountIncomingCancel;
		break;
	case sip_method_bye:
		++*mCountIncomingBye;
		break;
	case sip_method_message:
		++*mCountIncomingMessage;
		break;
	case sip_method_options:
		++*mCountIncomingOptions;
		break;
	default:
		if (strcmp(req->rq_method_name, "DECLINE")==0) {
			++*mCountIncomingDecline;
		} else {
			++*mCountIncomingReqUnknown;
		}
		break;
	}

662
	doSendEvent(ev, mModules.begin(), mModules.end());
663 664
}

665
void Agent::sendResponseEvent(shared_ptr<ResponseSipEvent> ev) {
666 667 668
	SLOGD << "Receiving new Response SIP message: "
	<< ev->getMsgSip()->mSip->sip_status->st_status << "\n"
	<< *ev->getMsgSip();
669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695

	sip_t *sip=ev->getMsgSip()->mSip;
	switch (sip->sip_status->st_status) {
	case 100:
		++*mCountIncoming100;
		break;
	case 101:
		++*mCountIncoming101;
		break;
	case 180:
		++*mCountIncoming180;
		break;
	case 200:
		++*mCountIncoming200;
		break;
	case 202:
		++*mCountIncoming202;
		break;
	case 401:
		++*mCountIncoming401;
		break;
	case 404:
		++*mCountIncoming404;
		break;
	case 407:
		++*mCountIncoming407;
		break;
696 697 698
	case 408:
		++*mCountIncoming408;
		break;
699 700 701
	case 486:
		++*mCountIncoming486;
		break;
702 703 704
	case 487:
		++*mCountIncoming487;
		break;
705 706 707 708 709 710 711 712 713 714 715
	case 488:
		++*mCountIncoming488;
		break;
	case 603:
		++*mCountIncoming603;
		break;
	default:
		++*mCountIncomingResUnknown;
		break;
	}

716
	doSendEvent(ev, mModules.begin(), mModules.end());
Yann Diorcet's avatar
Yann Diorcet committed
717 718
}

719
void Agent::injectRequestEvent(shared_ptr<RequestSipEvent> ev) {
720
	SLOGD << "Inject Request SIP message:\n" << *ev->getMsgSip();
721
	ev->restartProcessing();
722
	SLOGD << "Injecting request event after " << ev->mCurrModule->getModuleName();
723
	list<Module*>::iterator it;
724
	for (it = mModules.begin(); it != mModules.end(); ++it) {
725 726 727
		if (ev->mCurrModule == *it) {
			++it;
			break;
728
		}
729
	}
730 731

	doSendEvent(ev, it, mModules.end());
732 733
}

734
void Agent::injectResponseEvent(shared_ptr<ResponseSipEvent> ev) {
735
	SLOGD << "Inject Response SIP message:\n" << *ev->getMsgSip();
Yann Diorcet's avatar
Yann Diorcet committed
736 737
	list<Module*>::iterator it;
	ev->restartProcessing();
738
	SLOGD << "Injecting response event after " << ev->mCurrModule->getModuleName();
Yann Diorcet's avatar
Yann Diorcet committed
739 740 741 742 743 744
	for (it = mModules.begin(); it != mModules.end(); ++it) {
		if (ev->mCurrModule == *it) {
			++it;
			break;
		}
	}
745 746

	doSendEvent(ev, it, mModules.end());
Yann Diorcet's avatar
Yann Diorcet committed
747 748 749
}


750 751 752 753 754 755 756 757
/**
 * This is a dangerous function when called at the wrong time.
 * So we prefer an early abort with a stack trace.
 * Indeed, incoming tport is global in sofia and will be overwritten
 */
static std::shared_ptr<tport_t> getIncomingTport(const msg_t *orig, Agent *ag) {
	tport_t *primaries=nta_agent_tports(ag->getSofiaAgent());
	tport_t *tport=tport_delivered_by(primaries,orig);
758
	if (!tport) LOGA("tport not found");
759 760 761 762
	return shared_ptr<tport_t>(tport_ref(tport), tport_unref);
}


763
int Agent::onIncomingMessage(msg_t *msg, const sip_t *sip) {
764 765 766 767 768
	if (mTerminating) {
		// Avoid throwing a bad weak pointer on GatewayAdapter destruction
		LOGI("Skipping incoming message on expired agent");
		return -1;
	}
769
	// Assuming sip is derived from msg
770
	shared_ptr<MsgSip> ms(new MsgSip(msg));
Yann Diorcet's avatar
Yann Diorcet committed
771
	if (sip->sip_request) {
772 773
		auto inTport=getIncomingTport(msg, this);
		auto ev = make_shared<RequestSipEvent>(shared_from_this(), ms, inTport);
Yann Diorcet's avatar
Yann Diorcet committed
774
		sendRequestEvent(ev);
775
	} else {
776
		auto ev = make_shared<ResponseSipEvent>(shared_from_this(), ms);
Yann Diorcet's avatar
Yann Diorcet committed
777
		sendResponseEvent(ev);
778
	}
779
	msg_destroy(msg);
780
	return 0;
781 782
}

Yann Diorcet's avatar
Yann Diorcet committed
783 784 785
int Agent::messageCallback(nta_agent_magic_t *context, nta_agent_t *agent, msg_t *msg, sip_t *sip) {
	Agent *a = (Agent*) context;
	return a->onIncomingMessage(msg, sip);
786 787
}

Yann Diorcet's avatar
Yann Diorcet committed
788
void Agent::idle() {
789
	SLOGD << "In Agent::idle()";
Yann Diorcet's avatar
Yann Diorcet committed
790
	for_each(mModules.begin(), mModules.end(), mem_fun(&Module::idle));
791 792 793
	if (GenericManager::get()->mNeedRestart) {
		exit(RESTART_EXIT_CODE);
	}
794
}
795

Yann Diorcet's avatar
Yann Diorcet committed
796
const string& Agent::getUniqueId() const {
jehan's avatar
jehan committed
797 798
	return mUniqueId;
}
799

Yann Diorcet's avatar
Yann Diorcet committed
800 801
su_timer_t *Agent::createTimer(int milliseconds, timerCallback cb, void *data) {
	su_timer_t *timer = su_timer_create(su_root_task(mRoot), milliseconds);
802
	su_timer_set_for_ever(timer, (su_timer_f) cb, data);
Simon Morlat's avatar
Simon Morlat committed
803 804 805
	return timer;
}

Yann Diorcet's avatar
Yann Diorcet committed
806
void Agent::stopTimer(su_timer_t *t) {
Simon Morlat's avatar
Simon Morlat committed
807 808 809
	su_timer_destroy(t);
}

810
void Agent::send(const shared_ptr<MsgSip> &ms, url_string_t const *u, tag_type_t tag, tag_value_t value, ...) {
811 812
	ta_list ta;
	ta_start(ta, tag, value);
Yann Diorcet's avatar
Yann Diorcet committed
813
	msg_t* msg = msg_dup(ms->getMsg());
814
	nta_msg_tsend(mAgent, msg, u, ta_tags(ta),TAG_END());
815 816 817
	ta_end(ta);
}

818
void Agent::incrReplyStat(int status) {
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843
	switch (status) {
	case 100:
		++*mCountReply100;
		break;
	case 101:
		++*mCountReply101;
		break;
	case 180:
		++*mCountReply180;
		break;
	case 200:
		++*mCountReply200;
		break;
	case 202:
		++*mCountReply202;
		break;
	case 401:
		++*mCountReply401;
		break;
	case 404:
		++*mCountReply404;
		break;
	case 407:
		++*mCountReply407;
		break;
844 845 846
	case 408:
		++*mCountReply408;
		break;
847 848 849
	case 486:
		++*mCountReply486;
		break;
850 851 852
	case 487:
		++*mCountReply487;
		break;
853 854 855 856 857 858 859
	case 488:
		++*mCountReply488;
		break;
	default:
		++*mCountReplyResUnknown;
		break;
	}
860 861 862
}
void Agent::reply(const shared_ptr<MsgSip> &ms, int status, char const *phrase, tag_type_t tag, tag_value_t value, ...) {
	incrReplyStat(status);
863 864
	ta_list ta;
	ta_start(ta, tag, value);
865
	msg_t* msg = ms->createOrigMsgRef();
Yann Diorcet's avatar
Yann Diorcet committed
866
	nta_msg_treply(mAgent, msg, status, phrase, ta_tags(ta));
867 868 869
	ta_end(ta);
}