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

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.
9

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.
14

15 16
	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/>.
17
*/
Simon Morlat's avatar
Simon Morlat committed
18

19
#include <algorithm>
jehan's avatar
jehan committed
20
#include <sstream>
21 22 23 24 25 26

#include <net/if.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>

27
#include <sofia-sip/sip.h>
28
#include <sofia-sip/su_tagarg.h>
29
#include <sofia-sip/su_md5.h>
30
#include <sofia-sip/tport.h>
31
#include <sofia-sip/tport_tag.h>
32

33 34 35 36 37
#include <flexisip/agent.hh>
#include <flexisip/flexisip-version.h>
#include <flexisip/logmanager.hh>
#include <flexisip/module.hh>
#include <flexisip/registrardb.hh>
38

39 40 41
#include "etchosts.hh"
#include "domain-registrations.hh"
#include "plugin/plugin-loader.hh"
42

43 44
#define IPADDR_SIZE 64

45
using namespace std;
46 47

namespace flexisip {
48

49
static StatCounter64 *createCounter(GenericStruct *global, string keyprefix, string helpprefix, string value) {
50
	return global->createStat(keyprefix + value, helpprefix + value + ".");
51 52
}
void Agent::onDeclare(GenericStruct *root) {
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
	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");
	mCountIncoming408 = createCounter(global, key, help, "408");
	mCountIncoming486 = createCounter(global, key, help, "486");
	mCountIncoming487 = createCounter(global, key, help, "487");
	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");
	mCountReply408 = createCounter(global, key, help, "408"); // request timeout
	mCountReply486 = createCounter(global, key, help, "486");
	mCountReply487 = createCounter(global, key, help, "487"); // Request canceled
	mCountReply488 = createCounter(global, key, help, "488");
	mCountReplyResUnknown = createCounter(global, key, help, "unknown");
99

100
	string uniqueId = global->get<ConfigString>("unique-id")->read();
101 102
	if (!uniqueId.empty()) {
		if (uniqueId.length() == 16) {
103 104
			transform(uniqueId.begin(), uniqueId.end(), uniqueId.begin(), ::tolower);
			if(find_if(uniqueId.begin(), uniqueId.end(), [](char c)->bool{return !::isxdigit(c);}) == uniqueId.end()) {
105 106 107 108 109 110 111 112
				mUniqueId = uniqueId;
			} else {
				SLOGE << "'uniqueId' parameter must hold an hexadecimal number";
			}
		} else {
			SLOGE << "'uniqueId' parameter must have 16 characters. Skipping it";
		}
	}
113 114 115
}

void Agent::startLogWriter() {
116 117 118 119 120
	GenericStruct *cr = GenericManager::get()->getRoot()->get<GenericStruct>("event-logs");

	if (cr->get<ConfigBoolean>("enabled")->read()) {
		if (cr->get<ConfigString>("logger")->read() == "database") {
			#if ENABLE_SOCI
121 122

			DataBaseEventLogWriter *dbw = new DataBaseEventLogWriter(
123 124 125 126 127
				cr->get<ConfigString>("database-backend")->read(),
				cr->get<ConfigString>("database-connection-string")->read(),
				cr->get<ConfigInt>("database-max-queue-size")->read(),
				cr->get<ConfigInt>("database-nb-threads-max")->read()
			);
128
			if (!dbw->isReady()) {
129
				LOGF("DataBaseEventLogWriter: unable to use database.");
Margaux Clerc's avatar
Margaux Clerc committed
130
			} else {
131
				mLogWriter.reset(dbw);
Margaux Clerc's avatar
Margaux Clerc committed
132
			}
133 134
			#else
				LOGF("DataBaseEventLogWriter: unable to use database (`ENABLE_SOCI` is not defined).");
135
			#endif
Margaux Clerc's avatar
Margaux Clerc committed
136
		} else {
137
			string logdir = cr->get<ConfigString>("dir")->read();
138 139
			FilesystemEventLogWriter *lw = new FilesystemEventLogWriter(logdir);
			if (!lw->isReady()) {
Margaux Clerc's avatar
Margaux Clerc committed
140 141
				delete lw;
			} else {
142
				mLogWriter.reset(lw);
Margaux Clerc's avatar
Margaux Clerc committed
143 144
			}
		}
145 146
	}
}
147

148
static string absolutePath(const string &currdir, const string &file) {
149 150 151 152
	if (file.empty())
		return file;
	if (file.at(0) == '/')
		return file;
153 154 155
	return currdir + "/" + file;
}

156
void Agent::checkAllowedParams(const url_t *uri) {
157
	SofiaAutoHome home;
158 159
	if (!uri->url_params)
		return;
160 161 162 163 164
	char *params = su_strdup(home.home(), uri->url_params);
	/*remove all the allowed params and see if something else is remaning at the end*/
	params = url_strip_param_string(params, "tls-certificates-dir");
	params = url_strip_param_string(params, "require-peer-certificate");
	params = url_strip_param_string(params, "maddr");
165 166
	params = url_strip_param_string(params, "tls-verify-incoming");
	params = url_strip_param_string(params, "tls-verify-outgoing");
167 168
	// make sure that there is no misstyped params in the url:
	if (params && strlen(params) > 0) {
169 170 171 172
		LOGF("Bad parameters '%s' given in transports definition.", params);
	}
}

173 174
void Agent::initializePreferredRoute() {
	//Adding internal transport to transport in "cluster" case
175
	GenericStruct *cluster = GenericManager::get()->getRoot()->get<GenericStruct>("cluster");
176
	if (cluster->get<ConfigBoolean>("enabled")->read()) {
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
		int err = 0;
		string internalTransport = cluster->get<ConfigString>("internal-transport")->read();

		size_t pos = internalTransport.find("\%auto");
		if (pos != string::npos) {
			char result[NI_MAXHOST] = { 0 };
			//Currently only IpV4
			err = bctbx_get_local_ip_for(AF_INET, nullptr, 0, result, sizeof(result));
			if (err != 0) {
				LOGE("Could not get local ip");
			} else {
				internalTransport.replace(pos, sizeof("\%auto")-1, result);
			}
		}

		if (err == 0) {
193
			url_t *url = url_make(&mHome, internalTransport.c_str());
194 195 196

			if (url != nullptr) {
				mPreferredRouteV4 = url_hdup(&mHome, url);
197
				LOGD("Agent's preferred IP for internal routing find: v4: %s", internalTransport.c_str());
198 199 200 201 202
			}
		}
	}
}

203 204 205 206 207 208 209 210 211 212 213 214
void Agent::loadModules() {
	list<Module *>::iterator it;
	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();
		(*it)->load();
	}
	if (mDrm) mDrm->load(mPassphrase);
	mPassphrase = "";
}

215
bool getUriParameter(const url_t *url, const char *param, string &value){
216
	return ModuleToolbox::getUriParameter(url, param, value);
217 218 219
}

bool getBoolUriParameter(const url_t *url, const char *param, bool defaultValue){
220
	return ModuleToolbox::getBoolUriParameter(url, param, defaultValue);
221 222
}

223 224 225 226 227
#if ENABLE_MDNS
static void mDnsRegisterCallback(void *data, int error) {
	if (error != 0) LOGE("Error while registering a mDNS service");
}
#endif
228

229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254

void Agent::startMdns(){
#if ENABLE_MDNS
	/* Get Informations about mDNS register */
	GenericStruct *mdns = GenericManager::get()->getRoot()->get<GenericStruct>("mdns-register");
	bool mdnsEnabled = mdns->get<ConfigBoolean>("enabled")->read();
	if (mdnsEnabled) {
		if (!belle_sip_mdns_register_available()) LOGF("Belle-sip does not have mDNS activated!");

		string mdnsDomain = GenericManager::get()->getRoot()->get<GenericStruct>("cluster")->get<ConfigString>("cluster-domain")->read();
		int mdnsPrioMin = mdns->get<ConfigIntRange>("mdns-priority")->readMin();
		int mdnsPrioMax = mdns->get<ConfigIntRange>("mdns-priority")->readMax();
		int mdnsWeight = mdns->get<ConfigInt>("mdns-weight")->read();
		int mdnsTtl = mdns->get<ConfigInt>("mdns-ttl")->read();

		/* Get hostname of the machine */
		char hostname[HOST_NAME_MAX];
		int err = gethostname(hostname, sizeof(hostname));
		if (err != 0) {
			LOGE("Cannot retrieve machine hostname.");
		} else {
			int prio;
			if (mdnsPrioMin == mdnsPrioMax) {
				prio = mdnsPrioMin;
			} else {
				/* Randomize the priority */
255 256
				prio = belle_sip_random() % (mdnsPrioMax - mdnsPrioMin + 1) + mdnsPrioMin;
				LOGD("Multicast DNS services will be started with priority: %d", prio);
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
			}

			LOGD("Registering multicast DNS services.");
			for (tport_t *tport = tport_primaries(nta_agent_tports(mAgent)); tport != NULL; tport = tport_next(tport)) {
				char registerName[512];
				const tp_name_t *name = tport_name(tport);
				snprintf(registerName, sizeof(registerName), "%s_%s_%s", hostname, name->tpn_proto, name->tpn_port);

				belle_sip_mdns_register_t *reg = belle_sip_mdns_register("sip", name->tpn_proto, mdnsDomain.c_str(),
																		registerName, atoi(name->tpn_port), prio, mdnsWeight,
																		mdnsTtl, mDnsRegisterCallback, NULL);
				mMdnsRegisterList.push_back(reg);
			}
		}
	}
#endif
}

275 276 277 278
static void timerfunc(su_root_magic_t *magic, su_timer_t *t, Agent *a) {
	a->idle();
}

279
void Agent::start(const string &transport_override, const string passphrase) {
280 281 282 283 284 285
	char cCurrDir[FILENAME_MAX];
	if (!getcwd(cCurrDir, sizeof(cCurrDir))) {
		LOGA("Could not get current file path");
	}
	string currDir = cCurrDir;

286
	GenericStruct *global = GenericManager::get()->getRoot()->get<GenericStruct>("global");
287
	list<string> transports = global->get<ConfigStringList>("transports")->read();
288
	string ciphers = global->get<ConfigString>("tls-ciphers")->read();
289
	// sofia needs a value in millseconds.
290
	unsigned int tports_idle_timeout = 1000 * (unsigned int)global->get<ConfigInt>("idle-timeout")->read();
291
	bool globalVerifyIn = global->get<ConfigBoolean>("require-peer-certificate")->read();
292
	string mainTlsCertsDir = global->get<ConfigString>("tls-certificates-dir")->read();
293
	unsigned int t1x64 = (unsigned int)global->get<ConfigInt>("transaction-timeout")->read();
294
	int udpmtu = global->get<ConfigInt>("udp-mtu")->read();
295
	unsigned int incompleteIncomingMessageTimeout = 600 * 1000; /*milliseconds*/
296
	unsigned int keepAliveInterval = global->get<ConfigInt>("keepalive-interval")->read() * 1000;
297 298
	unsigned int queueSize = 256; /*number of SIP message that sofia can queue in a tport (a connection). It is 64 by default,
				hardcoded in sofia-sip. This is not sufficient for IM.*/
299

300
	mProxyToProxyKeepAliveInterval = global->get<ConfigInt>("proxy-to-proxy-keepalive-interval")->read() * 1000;
301

302 303 304
	mTimer = su_timer_create(su_root_task(mRoot), 5000);
	su_timer_set_for_ever(mTimer, reinterpret_cast<su_timer_f>(timerfunc), this);

305
	mainTlsCertsDir = absolutePath(currDir, mainTlsCertsDir);
306

307 308
	SLOGD << "Main tls certs dir : " << mainTlsCertsDir;

309 310 311 312
	nta_agent_set_params(mAgent, NTATAG_SIP_T1X64(t1x64), NTATAG_RPORT(1), NTATAG_TCP_RPORT(1),
						 NTATAG_TLS_RPORT(1), // use rport in vias added to outgoing requests for all protocols
						 NTATAG_SERVER_RPORT(2), // always add a rport parameter even if the request doesn't have it*/
						 NTATAG_UDP_MTU(udpmtu), TAG_END());
313

314 315
	if (!transport_override.empty()) {
		transports = ConfigStringList::parse(transport_override);
316 317
	}

318 319
	for (auto it = transports.begin(); it != transports.end(); ++it) {
		const string &uri = (*it);
320 321 322 323
		url_t *url;
		int err;
		su_home_t home;
		su_home_init(&home);
324 325 326
		url = url_make(&home, uri.c_str());
		LOGD("Enabling transport %s", uri.c_str());
		if (uri.find("sips") == 0) {
327
			string keys;
328 329
			string value;
			unsigned int tls_policy = 0;
330

331
			if (globalVerifyIn) tls_policy |= TPTLS_VERIFY_INCOMING;
332

333 334 335
			if (getUriParameter(url, "tls-certificates-dir", value)){
				keys = absolutePath(currDir, value);
			}else{
336
				keys = mainTlsCertsDir;
337
			}
338

339 340 341
			if (getBoolUriParameter(url, "tls-verify-incoming", false) || getBoolUriParameter(url, "require-peer-certificate", false)){
				tls_policy |= TPTLS_VERIFY_INCOMING;
			}
342

343
			if (getBoolUriParameter(url, "tls-verify-outgoing", true)){
344
				tls_policy |= TPTLS_VERIFY_OUTGOING | TPTLS_VERIFY_SUBJECTS_OUT;
345
			}
346

347
			checkAllowedParams(url);
348
			mPassphrase = passphrase;
349 350 351 352 353 354 355 356 357
			err = nta_agent_add_tport(
				mAgent, (const url_string_t *)url, TPTAG_CERTIFICATE(keys.c_str()),
				TPTAG_TLS_PASSPHRASE(mPassphrase.c_str()), TPTAG_TLS_CIPHERS(ciphers.c_str()),
				TPTAG_TLS_VERIFY_POLICY(tls_policy), TPTAG_IDLE(tports_idle_timeout),
				TPTAG_TIMEOUT(incompleteIncomingMessageTimeout),
				TPTAG_KEEPALIVE(keepAliveInterval), TPTAG_SDWN_ERROR(1),
				TPTAG_QUEUESIZE(queueSize),
				TAG_END()
			);
358
		} else {
359 360 361 362 363 364 365
			err = nta_agent_add_tport(
				mAgent, (const url_string_t *)url, TPTAG_IDLE(tports_idle_timeout),
				TPTAG_TIMEOUT(incompleteIncomingMessageTimeout),
				TPTAG_KEEPALIVE(keepAliveInterval), TPTAG_SDWN_ERROR(1),
				TPTAG_QUEUESIZE(queueSize),
				TAG_END()
			);
366
		}
367 368 369 370 371
		if (err == -1) {
			if (url_has_param(url, "transport")) {
				char transport[64] = {0};
				url_param(url->url_params, "transport", transport, sizeof(transport));
				if (strcasecmp(transport, "tls") == 0) {
372
					LOGF("Specifying an URI with transport=tls is not understood in flexisip configuration. Use 'sips' uri scheme "
373
						 "instead.");
374 375
				}
			}
376
			LOGF("Could not enable transport %s: %s", uri.c_str(), strerror(errno));
377 378 379
		}
		su_home_deinit(&home);
	}
380

381
	/* Setup the internal transport*/
382 383 384 385
	if (mPreferredRouteV4 != nullptr) {
		if (nta_agent_add_tport(
				mAgent, (const url_string_t *)mPreferredRouteV4, TPTAG_IDLE(tports_idle_timeout),
				TPTAG_TIMEOUT(incompleteIncomingMessageTimeout),
386
				TPTAG_IDENT(sInternalTransportIdent),
387
				TPTAG_KEEPALIVE(keepAliveInterval), TPTAG_QUEUESIZE(queueSize), TPTAG_SDWN_ERROR(1), TAG_END()
388 389 390
			) == -1) {
			char prefRouteV4[266];
			url_e(prefRouteV4, sizeof(prefRouteV4), mPreferredRouteV4);
391
			LOGF("Could not enable internal transport %s: %s", prefRouteV4, strerror(errno));
392
		}
393 394 395 396 397 398
		tp_name_t tn = {0};
		tn.tpn_ident = (char*)sInternalTransportIdent;
		mInternalTport = tport_by_name(nta_agent_tports(mAgent), &tn);
		if (!mInternalTport){
			LOGF("Could not obtain pointer to internal tport. Bug somewhere.");
		}
399 400
	}

401 402 403
	tport_t *primaries = tport_primaries(nta_agent_tports(mAgent));
	if (primaries == NULL)
		LOGF("No sip transport defined.");
404

405
	startMdns();
406

407
	/*
408 409
	 * Iterate on all the transports enabled or implicitely configured (case of 'sip:*') in order to guess useful
	 *information from an empiric manner:
410
	 * mPublicIpV4/mPublicIpV6 is the public IP of the proxy, assuming there's only one.
411 412 413 414
	 * 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.
415 416
	 * This algo is really empiric and aims at satisfy most common needs but cannot satisfy all of them.
	**/
417 418 419
	su_md5_t ctx;
	su_md5_init(&ctx);

420
	LOGD("Agent 's primaries are:");
421
	for (tport_t *tport = primaries; tport != NULL; tport = tport_next(tport)) {
422 423
		const tp_name_t *name;
		char url[512];
424
		name = tport_name(tport);
425
		snprintf(url, sizeof(url), "sip:%s:%s;transport=%s;maddr=%s", name->tpn_canon, name->tpn_port, name->tpn_proto, name->tpn_host);
426 427 428
		su_md5_strupdate(&ctx, url);
		LOGD("\t%s", url);
		bool isIpv6 = strchr(name->tpn_host, ':') != NULL;
429 430 431 432 433 434 435 436 437 438

		// 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
		// and maddr the real ip we listen on.
		// Useful for a scenario where the flexisip is behind a router.
		if (isIpv6 && mPublicIpV6.empty()) {
			mPublicIpV6 = ModuleToolbox::getHost(name->tpn_canon);
		} else if (!isIpv6 && mPublicIpV4.empty()) {
			mPublicIpV4 = name->tpn_canon;
439
		}
440

441
		if (mNodeUri == NULL) {
Benjamin REIS's avatar
Benjamin REIS committed
442
			mNodeUri = urlFromTportName(&mHome, name);
443 444 445 446 447
			string clusterDomain = GenericManager::get()->getRoot()->get<GenericStruct>("cluster")->get<ConfigString>("cluster-domain")->read();
			if (!clusterDomain.empty()) {
				tp_name_t tmp_name = *name;
				tmp_name.tpn_canon = clusterDomain.c_str();
				tmp_name.tpn_port = NULL;
448
				mClusterUri = urlFromTportName(&mHome, &tmp_name, true);
449 450
			}
		}
451
	}
452

453 454
	bool clusterModeEnabled = GenericManager::get()->getRoot()->get<GenericStruct>("cluster")->get<ConfigBoolean>("enabled")->read();
	mDefaultUri = (clusterModeEnabled && mClusterUri) ? mClusterUri : mNodeUri;
455

456
	mPublicResolvedIpV4 = computeResolvedPublicIp(mPublicIpV4, AF_INET);
457 458 459
	if (mPublicResolvedIpV4.empty()) {
		mPublicResolvedIpV4 = mRtpBindIp;
	}
460

461 462 463 464 465 466 467 468 469
	if (!mPublicIpV6.empty()){
		mPublicResolvedIpV6 = computeResolvedPublicIp(mPublicIpV6, AF_INET6);
	}else{
		/*attempt to resolve as ipv6, in case it is a hostname*/
		mPublicResolvedIpV6 = computeResolvedPublicIp(mPublicIpV4, AF_INET6);
		if (!mPublicResolvedIpV6.empty()){
			mPublicIpV6 = mPublicIpV4;
		}
	}
470 471 472
	if (mPublicResolvedIpV6.empty()) {
		mPublicResolvedIpV6 = mRtpBindIp6;
	}
473

474 475 476 477 478 479 480 481 482 483 484 485
	// Generate the unique ID if it has not been specified in Flexisip's settings
	if (mUniqueId.empty()) {
		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;
		SLOGD << "Generating the unique ID: " << mUniqueId;
	} else {
		SLOGD << "Static unique ID: " << mUniqueId;
	}
486

487 488 489
	if (mPublicResolvedIpV6.empty() && mPublicResolvedIpV4.empty()){
		LOGF("The default public address of the server could not be resolved (%s / %s). Cannot continue.",mPublicIpV4.c_str(), mPublicIpV6.c_str());
	}
490

491 492 493 494
	LOGD("Agent public hostname/ip: v4:%s v6:%s", mPublicIpV4.c_str(), mPublicIpV6.c_str());
	LOGD("Agent public resolved hostname/ip: v4:%s v6:%s", mPublicResolvedIpV4.c_str(), mPublicResolvedIpV6.c_str());
	LOGD("Agent's _default_ RTP bind ip address: v4:%s v6:%s", mRtpBindIp.c_str(), mRtpBindIp6.c_str());

495
	mUseMaddr = GenericManager::get()->getGlobal()->get<ConfigBoolean>("use-maddr")->read();
496
	startLogWriter();
497 498

	loadModules();
499 500
}

501 502 503 504
// -----------------------------------------------------------------------------
// Helpers to build module instances.
// -----------------------------------------------------------------------------

505 506 507 508 509
static bool moduleIsBefore(const string &moduleName, ModuleInfoBase *next) {
	for (const string &after : next->getAfter()) {
		if (moduleName == after)
			return true;

510
		const list<ModuleInfoBase *> &registeredModuleInfo = ModuleInfoManager::get()->getRegisteredModuleInfo();
511 512 513 514 515 516 517 518 519 520
		auto it = find_if(registeredModuleInfo.cbegin(), registeredModuleInfo.cend(), [&after](const ModuleInfoBase *moduleInfo) {
			return moduleInfo->getModuleName() == after;
		});
		if (it != registeredModuleInfo.cend())
			return moduleIsBefore(moduleName, *it);
	}

	return false;
}

521 522 523
static list<ModuleInfoBase *> sortModuleInfoByPriority(list<ModuleInfoBase *> moduleInfoToSort) {
	// 1. Order each module info by priority.
	moduleInfoToSort.sort([](ModuleInfoBase *a, ModuleInfoBase *b) {
524 525 526 527 528 529
		const string &moduleName = a->getModuleName();
		if (moduleName.empty()) // Special case, root.
			return true;

		return moduleIsBefore(moduleName, b);
	});
530

531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
	// 2. Check if each module info has a valid ancestor.
	auto it = moduleInfoToSort.cbegin();
	if ((*it)->getModuleName().empty())
		LOGA("Unable to find the root of registered module info list.");

	bool soFarSoGood = true;
	auto prev = it;
	for (++it; it != moduleInfoToSort.cend(); prev = it, ++it) {
		const string &moduleName = (*prev)->getModuleName();
		for (const string &after : (*it)->getAfter())
			if (moduleName == after)
				goto success;

		soFarSoGood = false;
		SLOGE << "Unable to find a valid ancestor for [" << (*it)->getModuleName() << "]. "
			"Please to check your `after` predicate.";

		success:;
	}
	if (!soFarSoGood)
		LOGA("It's necessary to fix module info list to continue.");

	return moduleInfoToSort;
}

void addPluginModule(Agent *agent, list<Module *> &modules, const string &pluginDir, const string &pluginName) {
	SLOGI << "Loading [" << pluginName << "] plugin...";
	PluginLoader pluginLoader(agent, pluginDir + "/lib" + pluginName + ".so");

	const ModuleInfoBase *moduleInfo = pluginLoader.getModuleInfo();
	if (!moduleInfo) {
		SLOGE << "Unable to get module info of [" << pluginName << "] plugin (" << pluginLoader.getError() << ").";
		return;
	}
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
	const string &moduleName = moduleInfo->getModuleName();
	Module *module = pluginLoader.get();

	const string &replace = moduleInfo->getReplace();
	if (!replace.empty()) {
		auto it = find_if(modules.begin(), modules.end(), [&replace](const Module *module) {
			return module->getModuleName() == replace;
		});
		if (it == modules.end()) {
			SLOGE << "Unable to find module [" << replace << "]'s instance to be replaced by module [" << moduleName << "]'s instance";
			return;
		}
		
		SLOGW << "Creating plugin module " << "[" << moduleName << "]'s instance that will replace module [" << replace << "]'s instance.";
		// Replace the previous module by the new one in the chain
		it = modules.erase(it);
		modules.insert(it, module);
		return;
	}
584 585

	for (const string &after : moduleInfo->getAfter()) {
586 587 588
		// TODO: Replace begin() and end() with cbegin() and cend() later.
		// gcc 4.8.2 (CentOS 7) does not support insert with const iterator.
		auto it = find_if(modules.begin(), modules.end(), [&after](const Module *module) {
589 590
			return module->getModuleName() == after;
		});
591
		if (it == modules.end())
592 593
			continue;

594
		if (!module) {
595
			SLOGE << "Failed to load [" << moduleName << "] (" << pluginLoader.getError() << ").";
596
		} else {
597 598 599
			SLOGI << "Creating plugin module instance of " << "[" << moduleName << "] after [" << after << "].";
			modules.insert(++it, module);
		}
600
		return;
601 602 603 604 605 606 607
	}

	SLOGE << "Unable to find a valid ancestor for [" << pluginName << "] plugin.";
}

// -----------------------------------------------------------------------------

608
Agent::Agent(su_root_t *root) : mBaseConfigListener(NULL), mTerminating(false) {
609
	mHttpEngine = nth_engine_create(root, NTHTAG_ERROR_MSG(0), TAG_END());
610
	GenericStruct *cr = GenericManager::get()->getRoot();
611

612
	EtcHostsResolver::get();
613

614 615 616 617 618
	// 1. Create module instances.
	for (ModuleInfoBase *moduleInfo : sortModuleInfoByPriority(ModuleInfoManager::get()->getRegisteredModuleInfo())) {
		SLOGI << "Creating module instance of " << "[" << moduleInfo->getModuleName() << "].";
		mModules.push_back(moduleInfo->create(this));
	}
jehan's avatar
jehan committed
619

620
	// 2. Create module instances from plugins.
621 622 623
	{
		GenericStruct *global = cr->get<GenericStruct>("global");
		const string &pluginDir = global->get<ConfigString>("plugins-dir")->read();
624 625
		for (const string &pluginName : global->get<ConfigStringList>("plugins")->read())
			addPluginModule(this, mModules, pluginDir, pluginName);
626
	}
627

628
	mServerString = "Flexisip/" FLEXISIP_GIT_VERSION " (sofia-sip-nta/" NTA_VERSION ")";
629

630 631
	for (Module *module : mModules)
		module->declare(cr);
632

633
	onDeclare(cr);
634

635 636 637
	struct ifaddrs *net_addrs;
	int err = getifaddrs(&net_addrs);
	if (err == 0) {
638
		struct ifaddrs *ifa = net_addrs;
639 640 641 642 643 644 645
		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;
		}
646
		freeifaddrs(net_addrs);
647 648 649
	} else {
		LOGE("Can't find interface addresses: %s", strerror(err));
	}
650
	mRoot = root;
651
	mAgent = nta_agent_create(root, (url_string_t *)-1, &Agent::messageCallback, (nta_agent_magic_t *)this, TAG_END());
652
	su_home_init(&mHome);
653 654
	mPreferredRouteV4 = NULL;
	mPreferredRouteV6 = NULL;
655
	mDrm = new DomainRegistrationManager(this);
656
	mProxyToProxyKeepAliveInterval = 0;
657 658
}

Yann Diorcet's avatar
Yann Diorcet committed
659
Agent::~Agent() {
660 661 662 663 664 665
#if ENABLE_MDNS
	for(belle_sip_mdns_register_t *reg : mMdnsRegisterList) {
		belle_sip_mdns_unregister(reg);
	}
#endif

666
	mTerminating = true;
667 668
	for (Module *module : mModules)
		delete module;
669

670 671
	if (mTimer)
		su_timer_destroy(mTimer);
672 673 674 675 676 677
	if (mDrm)
		delete mDrm;
	if (mAgent)
		nta_agent_destroy(mAgent);
	if (mHttpEngine)
		nth_engine_destroy(mHttpEngine);
678
	su_home_deinit(&mHome);
679 680
}

Yann Diorcet's avatar
Yann Diorcet committed
681
const char *Agent::getServerString() const {
682 683 684
	return mServerString.c_str();
}

685
string Agent::getPreferredRoute() const {
686 687
	if (!mPreferredRouteV4)
		return string();
688

689
	char prefUrl[266];
690
	url_e(prefUrl, sizeof(prefUrl), mPreferredRouteV4);
691 692 693
	return string(prefUrl);
}

694
bool Agent::doOnConfigStateChanged(const ConfigValue &conf, ConfigState state) {
695
	LOGD("Configuration of agent changed for key %s to %s", conf.getName().c_str(), conf.get().c_str());
696 697

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

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

706
void Agent::loadConfig(GenericManager *cm) {
707
	cm->loadStrict(); // now that each module has declared its settings, we need to reload from the config file
708
	if (!mBaseConfigListener) {
709
		mBaseConfigListener = cm->getGlobal()->getConfigListener();
710 711 712
	}
	cm->getRoot()->get<GenericStruct>("global")->setConfigListener(this);
	mAliases = cm->getGlobal()->get<ConfigStringList>("aliases")->read();
Simon Morlat's avatar
Simon Morlat committed
713
	LOGD("List of host aliases:");
Yann Diorcet's avatar
Yann Diorcet committed
714 715
	for (list<string>::iterator it = mAliases.begin(); it != mAliases.end(); ++it) {
		LOGD("%s", (*it).c_str());
Simon Morlat's avatar
Simon Morlat committed
716
	}
717

718
	RegistrarDb::initialize(this);
719

720
	initializePreferredRoute();
Simon Morlat's avatar
Simon Morlat committed
721 722
}

723 724 725 726 727 728 729
void Agent::unloadConfig() {
	list<Module *>::iterator it;
	for (it = mModules.begin(); it != mModules.end(); ++it) {
		(*it)->unload();
	}
}

730
string Agent::computeResolvedPublicIp(const string &host, int family) const {
731 732
	int err;
	struct addrinfo hints;
733
	string dest;
734
	memset(&hints, 0, sizeof(hints));
735
	hints.ai_family = family;
736
	struct addrinfo *result;
737 738 739 740 741 742

	dest.clear();
	if (host.empty())
		return dest;
	dest = (host[0] == '[') ? host.substr(1, host.size() - 2) : host;

743 744 745 746
	err = getaddrinfo(dest.c_str(), NULL, &hints, &result);
	if (err == 0) {
		char ip[NI_MAXHOST];
		err = getnameinfo(result->ai_addr, result->ai_addrlen, ip, sizeof(ip), NULL, 0, NI_NUMERICHOST);
747
		freeaddrinfo(result);
748 749 750
		if (err == 0) {
			return ip;
		} else {
751
			LOGE("getnameinfo error: %s for host [%s]", gai_strerror(err), host.c_str());
752 753
		}
	} else {
754
		LOGW("getaddrinfo error: %s for host [%s] and family=[%i]", gai_strerror(err), host.c_str(), family);
755
	}
756
	return "";
757
}
758

759
pair<string, string> Agent::getPreferredIp(const string &destination) const {
760
	int err;
761
	struct addrinfo hints;
762
	string dest = (destination[0] == '[') ? destination.substr(1, destination.size() - 2) : destination;
763 764 765
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_flags = AI_NUMERICHOST;
766

767
	struct addrinfo *result;
768
	err = getaddrinfo(dest.c_str(), NULL, &hints, &result);
769 770 771 772
	if (err == 0) {
		for (auto it = mNetworks.begin(); it != mNetworks.end(); ++it) {
			if (it->isInNetwork(result->ai_addr)) {
				freeaddrinfo(result);
773
				return make_pair(it->getIP(), it->getIP());
774 775
			}
		}
776 777
		freeaddrinfo(result);
	} else {
Simon Morlat's avatar
Simon Morlat committed
778
		LOGE("getPreferredIp() getaddrinfo() error while resolving '%s': %s", dest.c_str(), gai_strerror(err));
779
	}
780 781
	return strchr(dest.c_str(), ':') == NULL ? make_pair(getResolvedPublicIp(), getRtpBindIp())
											 : make_pair(getResolvedPublicIp(true), getRtpBindIp(true));
782 783
}

784
Agent::Network::Network(const Network &net) : mIP(net.mIP) {
785 786
	memcpy(&mPrefix, &net.mPrefix, sizeof(mPrefix));
	memcpy(&mMask, &net.mMask, sizeof(mMask));
787 788
}

789
Agent::Network::Network(const struct ifaddrs *ifaddr) {
790
	int err = 0;
791
	char ipAddress[IPADDR_SIZE];
792 793
	memset(&mPrefix, 0, sizeof(mPrefix));
	memset(&mMask, 0, sizeof(mMask));
794
	if (ifaddr->ifa_addr->sa_family == AF_INET) {
795
		typedef struct sockaddr_in sockt;
796 797 798 799
		sockt *if_addr = (sockt *)ifaddr->ifa_addr;
		sockt *if_mask = (sockt *)ifaddr->ifa_netmask;
		sockt *prefix = (sockt *)&mPrefix;
		sockt *mask = (sockt *)&mMask;
800 801 802 803 804

		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);
805
	} else if (ifaddr->ifa_addr->sa_family == AF_INET6) {
806
		typedef struct sockaddr_in6 sockt;
807 808 809 810
		sockt *if_addr = (sockt *)ifaddr->ifa_addr;
		sockt *if_mask = (sockt *)ifaddr->ifa_netmask;
		sockt *prefix = (sockt *)&mPrefix;
		sockt *mask = (sockt *)&mMask;
811 812 813 814 815

		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];
816
		}
817
		err = getnameinfo(ifaddr->ifa_addr, sizeof(sockt), ipAddress, IPADDR_SIZE, NULL, 0, NI_NUMERICHOST);
818 819 820 821 822 823 824 825 826 827 828 829 830
	}
	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 {
831
	if (addr->sa_family != mPrefix.ss_family) {
832 833
		return false;
	}
834

835
	if (addr->sa_family == AF_INET) {
836
		typedef struct sockaddr_in sockt;
837 838 839
		sockt *prefix = (sockt *)&mPrefix;
		sockt *mask = (sockt *)&mMask;
		sockt *if_addr = (sockt *)addr;
840 841 842

		uint32_t test = if_addr->sin_addr.s_addr & mask->sin_addr.s_addr;
		return test == prefix->sin_addr.s_addr;
843
	} else if (addr->sa_family == AF_INET6) {
844
		typedef struct sockaddr_in6 sockt;
845 846 847
		sockt *prefix = (sockt *)&mPrefix;
		sockt *mask = (sockt *)&mMask;
		sockt *if_addr = (sockt *)addr;
848 849 850 851

		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])
852 853
				return false;
		}
854 855 856
		return true;
	} else {
		LOGF("Network::isInNetwork: cannot happen");
857 858 859 860 861 862
	}
}

string Agent::Network::print(const struct ifaddrs *ifaddr) {
	stringstream ss;
	int err;
863 864
	unsigned int size =
		(ifaddr->ifa_addr->sa_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
865 866 867
	char result[IPADDR_SIZE];
	ss << "Name: " << ifaddr->ifa_name;

868
	err = getnameinfo(ifaddr->ifa_addr, size, result, IPADDR_SIZE, NULL, 0, NI_NUMERICHOST);
869
	if (err != 0) {
870
		ss << "\tAddress: " << "(Error)";
871 872 873
	} else {
		ss << "\tAddress: " << result;
	}
874
	err = getnameinfo(ifaddr->ifa_netmask, size, result, IPADDR_SIZE, NULL, 0, NI_NUMERICHOST);
875
	if (err != 0) {
876
		ss << "\tMask: " << "(Error)";
877 878 879 880 881
	} else {
		ss << "\tMask: " << result;
	}

	return ss.str();
Simon Morlat's avatar
Simon Morlat committed
882 883
}

Yann Diorcet's avatar
Yann Diorcet committed
884
int Agent::countUsInVia(sip_via_t *via) const {
885
	int count = 0;
Yann Diorcet's avatar
Yann Diorcet committed
886 887 888
	for (sip_via_t *v = via; v != NULL; v = v->v_next) {
		if (isUs(v->v_host, v->v_port, true))
			++count;
889 890 891 892 893
	}

	return count;
}

Yann Diorcet's avatar
Yann Diorcet committed
894 895
bool Agent::isUs(const char *host, const char *port, bool check_aliases) const {
	char *tmp = NULL;
896
	size_t end;
897
	tport_t *tport = tport_primaries(nta_agent_tports(mAgent));
898

899
	// skip possibly trailing '.' at the end of host
Yann Diorcet's avatar
Yann Diorcet committed
900
	if (host[end = (strlen(host) - 1)] == '.') {
901
		tmp = (char *)alloca(end + 1);
Yann Diorcet's avatar
Yann Diorcet committed
902 903 904
		memcpy(tmp, host, end);
		tmp[end] = '\0';
		host = tmp;
905
	}
906 907
	const char *matched_port = port;

Simon Morlat's avatar
Simon Morlat committed
908
	if (check_aliases) {
909 910
		/*the checking of aliases ignores the port number, since a domain name in a Route header might resolve to
		 * multiple ports
Simon Morlat's avatar
Simon Morlat committed
911 912 913 914 915 916 917
			* thanks to SRV records*/
		list<string>::const_iterator it;
		for (it = mAliases.begin(); it != mAliases.end(); ++it) {
			if (ModuleToolbox::urlHostMatch(host, (*it).c_str()))
				return true;
		}
	}
918 919 920 921 922 923 924 925

	for (; tport != NULL; tport = tport_next(tport)) {
		const tp_name_t *tn = tport_name(tport);
		if (port == NULL) {
			if (strcasecmp(tn->tpn_proto, "tls") == 0)
				matched_port = "5061";
			else
				matched_port = "5060";
926
		}
927
		if (strcmp(matched_port, tn->tpn_port) == 0) {
jehan's avatar
jehan committed
928
			if (ModuleToolbox::urlHostMatch(host, tn->tpn_canon) || ModuleToolbox::urlHostMatch(host, tn->tpn_host))
Yann Diorcet's avatar
Yann Diorcet committed
929
				return true;
Simon Morlat's avatar
Simon Morlat committed
930
		}
Simon Morlat's avatar
Simon Morlat committed
931 932
	}
	return false;
Simon Morlat's avatar
Simon Morlat committed
933 934
}

Yann Diorcet's avatar
Yann Diorcet committed
935
sip_via_t *Agent::getNextVia(sip_t *response) {
Simon Morlat's avatar
Simon Morlat committed
936
	sip_via_t *via;
Yann Diorcet's avatar
Yann Diorcet committed
937
	for (via = response->sip_via; via != NULL; via = via->v_next) {
938
		if (!isUs(via->v_host, via->v_port, false))
Simon Morlat's avatar
Simon Morlat committed
939 940 941 942 943
			return via;
	}
	return NULL;
}

944 945 946
/**
 * Takes care of an eventual maddr parameter.
 */
Yann Diorcet's avatar
Yann Diorcet committed
947
bool Agent::isUs(const url_t *url, bool check_aliases) const {
948
	char maddr[50];
949 950
	if (mDrm && mDrm->isUs(url))
		return true;
951 952 953
	if (url_param(url->url_params, "maddr", maddr, sizeof(maddr))) {
		return isUs(maddr, url->url_port, check_aliases);
	}
954
	return isUs(url->url_host, url->url_port, check_aliases);
Yann Diorcet's avatar
Yann Diorcet committed
955 956
}

957 958
void Agent::logEvent(const shared_ptr<SipEvent> &ev) {
	if (mLogWriter) {
959
		shared_ptr<EventLog> evlog;
960 961 962
		if ((evlog = ev->getEventLog<EventLog>())) {
			if (evlog->isCompleted())
				mLogWriter->write(evlog);
963 964 965 966
		}
	}
}

967
struct ModuleHasName {
968
	ModuleHasName(const string &ref) : match(ref) {
969 970 971 972 973 974
	}
	bool operator()(Module *module) {
		return module->getModuleName() == match;
	}
	const string &match;
};
975 976
Module *Agent::findModule(const string &moduleName) const {
	auto it = find_if(mModules.begin(), mModules.end(), ModuleHasName(moduleName));
977 978 979
	return (it != mModules.end()) ? *it : NULL;
}

980
template <typename SipEventT>
981 982 983
inline void Agent::doSendEvent(
	shared_ptr<SipEventT> ev, const list<Module *>::iterator &begin, const list<Module *>::iterator &end
) {
984 985 986 987 988 989 990 991
	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");
992
	}
993 994
}

995
void Agent::sendRequestEvent(shared_ptr<RequestSipEvent> ev) {
996
	SipLogContext ctx(ev->getMsgSip());
997 998 999 1000
	sip_t *sip = ev->getMsgSip()->getSip();
	const sip_request_t *req = sip->sip_request;
	const url_t *from_url = sip->sip_from ? sip->sip_from->a_url : NULL;

1001 1002 1003 1004 1005
	if (LOGD_ENABLED()){
		SLOGD << "Receiving new Request SIP message " << req->rq_method_name << " from "
			<< (from_url ? url_as_string(ev->getHome(), from_url) : "<invalid from>") << " :"
			<< "\n" << *ev->getMsgSip();
	}
1006
	switch (req->rq_method) {
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
		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;
1038 1039
	}

1040
	doSendEvent(ev, mModules.begin(), mModules.end());
1041 1042
}

1043
void Agent::sendResponseEvent(shared_ptr<ResponseSipEvent> ev) {
1044 1045 1046 1047 1048
	if (mTerminating) {
		// Avoid throwing a bad weak pointer on GatewayAdapter destruction
		LOGI("Skipping incoming message on expired agent");
		return;
	}
1049
	SipLogContext ctx(ev->getMsgSip());
1050 1051 1052
	
	if (LOGD_ENABLED()){
		SLOGD << "Receiving new Response SIP message: " << ev->getMsgSip()->getSip()->sip_status->st_status << "\n"
1053
		<< *ev->getMsgSip();
1054
	}
1055

1056
	sip_t *sip = ev->getMsgSip()->getSip();
1057
	switch (sip->sip_status->st_status) {
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099
		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;
		case 408:
			++*mCountIncoming408;
			break;
		case 486:
			++*mCountIncoming486;
			break;
		case 487:
			++*mCountIncoming487;
			break;
		case 488:
			++*mCountIncoming488;
			break;
		case 603:
			++*mCountIncoming603;
			break;
		default:
			++*mCountIncomingResUnknown;
			break;
1100 1101
	}

1102
	doSendEvent(ev, mModules.begin(), mModules.end());
Yann Diorcet's avatar
Yann Diorcet committed
1103 1104
}

1105
void Agent::injectRequestEvent(shared_ptr<RequestSipEvent> ev) {
1106
	SipLogContext ctx(ev->getMsgSip());
1107 1108 1109
	if (LOGD_ENABLED()){
		SLOGD << "Inject request SIP event after " << ev->mCurrModule->getModuleName() << ":\n" << *ev->getMsgSip();
	}
1110
	ev->restartProcessing();
1111
	list<Module *>::iterator it;
1112
	for (it = mModules.begin(); it != mModules.end(); ++it) {
1113 1114 1115
		if (ev->mCurrModule == *it) {
			++it;
			break;
1116
		}
1117
	}
1118
	doSendEvent(ev, it, mModules.end());
1119 1120
}

1121
void Agent::injectResponseEvent(shared_ptr<ResponseSipEvent> ev) {
1122
	SipLogContext ctx(ev->getMsgSip());
1123 1124 1125 1126
	
	if (LOGD_ENABLED()){
		SLOGD << "Injecting response SIP event after " << ev->mCurrModule->getModuleName() << ":\n" << *ev->getMsgSip();
	}
1127
	list<Module *>::iterator it;
Yann Diorcet's avatar
Yann Diorcet committed
1128 1129 1130 1131 1132 1133 1134
	ev->restartProcessing();
	for (it = mModules.begin(); it != mModules.end(); ++it) {
		if (ev->mCurrModule == *it) {
			++it;
			break;
		}
	}
1135
	doSendEvent(ev, it, mModules.end());
Yann Diorcet's avatar
Yann Diorcet committed
1136 1137
}

1138 1139 1140 1141 1142
/**
 * 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
 */
1143 1144 1145 1146 1147
static 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);
	if (!tport)
		LOGA("tport not found");
1148
	return tport;
1149 1150
}

1151
int Agent::onIncomingMessage(msg_t *msg, const sip_t *sip) {
1152 1153 1154 1155 1156
	if (mTerminating) {
		// Avoid throwing a bad weak pointer on GatewayAdapter destruction
		LOGI("Skipping incoming message on expired agent");
		return -1;
	}
1157
	// Assuming sip is derived from msg
1158
	shared_ptr<MsgSip> ms = make_shared<MsgSip>(msg);
Yann Diorcet's avatar
Yann Diorcet committed
1159
	if (sip->sip_request) {
1160
		auto ev = make_shared<RequestSipEvent>(shared_from_this(), ms, getIncomingTport(msg, this));
Yann Diorcet's avatar
Yann Diorcet committed
1161
		sendRequestEvent(ev);
1162
	} else {
1163
		auto ev = make_shared<ResponseSipEvent>(shared_from_this(), ms);
Yann Diorcet's avatar
Yann Diorcet committed
1164
		sendResponseEvent(ev);
1165
	}
1166
	msg_destroy(msg);
1167
	return 0;
1168 1169
}

1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
url_t* Agent::urlFromTportName(su_home_t* home, const tp_name_t* name, bool avoidMAddr) {
	url_t *url = NULL;
	url_type_e ut = url_sip;

	if (strcasecmp(name->tpn_proto, "tls") == 0)
		ut = url_sips;

	url = (url_t *)su_alloc(home, sizeof(url_t));
	url_init(url, ut);

	if (strcasecmp(name->tpn_proto, "tcp") == 0)
		url_param_add(home, url, "transport=tcp");

	url->url_port = su_strdup(home, name->tpn_port);
	url->url_host = su_strdup(home, name->tpn_canon);
	if (
		ut == url_sips
		&& !avoidMAddr
		&& (strcmp(name->tpn_host, name->tpn_canon) != 0)
1189
		&& mUseMaddr
1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
	) {
		const string &resolvedIp = strchr(name->tpn_host, ':')
			? mPublicResolvedIpV6
			: mPublicResolvedIpV4;
		url_param_add(home, url, su_sprintf(home, "maddr=%s", resolvedIp.c_str()));
	}

	return url;
}

Yann Diorcet's avatar
Yann Diorcet committed
1200
int Agent::messageCallback(nta_agent_magic_t *context, nta_agent_t *agent, msg_t *msg, sip_t *sip) {
1201
	Agent *a = (Agent *)context;
Yann Diorcet's avatar
Yann Diorcet committed
1202
	return a->onIncomingMessage(msg, sip);
1203 1204
}

Yann Diorcet's avatar
Yann Diorcet committed
1205 1206
void Agent::idle() {
	for_each(mModules.begin(), mModules.end(), mem_fun(&Module::idle));
1207
	if (GenericManager::get()->mNeedRestart) {
1208 1209
		exit(RESTART_EXIT_CODE);
	}
1210
}
1211

1212
const string &Agent::getUniqueId() const {
jehan's avatar
jehan committed
1213 1214
	return mUniqueId;
}
1215

1216
su_timer_t *Agent::createTimer(int milliseconds, timerCallback cb, void *data, bool repeating) {
Yann Diorcet's avatar
Yann Diorcet committed
1217
	su_timer_t *timer = su_timer_create(su_root_task(mRoot