event.cc 12.2 KB
Newer Older
Yann Diorcet's avatar
Yann Diorcet 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
*/
Yann Diorcet's avatar
Yann Diorcet committed
18

19 20 21 22 23
#include <flexisip/agent.hh>
#include <flexisip/event.hh>
#include <flexisip/transaction.hh>
#include <flexisip/common.hh>
#include <flexisip/module.hh>
Yann Diorcet's avatar
Yann Diorcet committed
24
#include <sofia-sip/sip_protos.h>
Yann Diorcet's avatar
Yann Diorcet committed
25
#include <sofia-sip/su_tagarg.h>
Simon Morlat's avatar
Simon Morlat committed
26
#include <sofia-sip/msg_addr.h>
Yann Diorcet's avatar
Yann Diorcet committed
27

28
using namespace std;
29 30

namespace flexisip {
Yann Diorcet's avatar
Yann Diorcet committed
31

32 33
void MsgSip::assignMsg(msg_t *msg) {
	mMsg = msg_ref_create(msg);
34
}
35

36
MsgSip::MsgSip(msg_t *msg) {
37
	assignMsg(msg);
38 39
}

40
/*Invoking the copy constructor of MsgSip implies the deep copy of the underlying msg_t */
Yann Diorcet's avatar
Yann Diorcet committed
41
MsgSip::MsgSip(const MsgSip &msgSip) {
42
	msgSip.serialize();
43
	msg_t *freshCopy = msg_dup(msgSip.mMsg);
44 45
	assignMsg(freshCopy);
	msg_destroy(freshCopy);
46
	LOGD("New MsgSip %p copied from MsgSip %p", this, &msgSip);
47 48
}

49 50 51 52 53 54 55 56 57 58 59 60 61
msg_header_t *MsgSip::findHeader(const std::string &name) {
	const sip_t *sip = getSip();
	auto begin = reinterpret_cast<msg_header_t * const *>(&sip->sip_via);
	auto end = reinterpret_cast<msg_header_t * const *>(&sip->sip_unknown);
	for (auto it = begin; it < end; it++) {
		msg_header_t *header = *it;
		if (header && strcasecmp(header->sh_common->h_class->hc_name, name.c_str()) == 0) {
			return header;
		}
	}
	return nullptr;
}

62 63
const char *MsgSip::print() {
	// make sure the message is serialized before showing it; it can be very confusing.
64
	size_t msg_size;
65
	msg_serialize(mMsg, (msg_pub_t *)getSip());
66
	return msg_as_string(getHome(), mMsg, NULL, 0, &msg_size);
Yann Diorcet's avatar
Yann Diorcet committed
67 68
}

Yann Diorcet's avatar
Yann Diorcet committed
69
MsgSip::~MsgSip() {
70
	// LOGD("Destroy MsgSip %p", this);
Yann Diorcet's avatar
Yann Diorcet committed
71 72
	msg_destroy(mMsg);
}
73

74 75
SipEvent::SipEvent(const shared_ptr<IncomingAgent> &inAgent, const shared_ptr<MsgSip> &msgSip)
	: mCurrModule(NULL), mMsgSip(msgSip), mState(STARTED) {
76
	LOGD("New SipEvent %p - msg %p", this, msgSip->getMsg());
77
	mIncomingAgent = inAgent;
78 79 80
	mAgent = inAgent->getAgent();
	shared_ptr<IncomingTransaction> it = dynamic_pointer_cast<IncomingTransaction>(inAgent);
	if (it) {
81
		mOutgoingAgent = it->mOutgoing;
82
	} else {
83 84
		mOutgoingAgent = inAgent->getAgent()->shared_from_this();
	}
Yann Diorcet's avatar
Yann Diorcet committed
85
}
86

87 88
SipEvent::SipEvent(const shared_ptr<OutgoingAgent> &outAgent, const shared_ptr<MsgSip> &msgSip)
	: mCurrModule(NULL), mMsgSip(msgSip), mState(STARTED) {
89
	LOGD("New SipEvent %p - %p", this, msgSip->getMsg());
90
	mOutgoingAgent = outAgent;
91 92 93 94 95 96 97 98 99 100 101
	mAgent = outAgent->getAgent();
	shared_ptr<OutgoingTransaction> ot = dynamic_pointer_cast<OutgoingTransaction>(outAgent);
	if (ot) {
		// retrieve the incoming transaction associated with the outgoing one, if any.
		// A response SipEvent is generated either from a stateless response or from a response from an outgoing
		// transaction.
		mIncomingAgent = ot->mIncoming;
	} else
		mIncomingAgent = mAgent->shared_from_this();
}

102 103
SipEvent::SipEvent(const SipEvent &sipEvent): enable_shared_from_this<SipEvent>(),
	  mCurrModule(sipEvent.mCurrModule), mIncomingAgent(sipEvent.mIncomingAgent),
104
	  mOutgoingAgent(sipEvent.mOutgoingAgent), mAgent(sipEvent.mAgent), mState(sipEvent.mState) {
105
	LOGD("New SipEvent %p with state %s", this, stateStr(mState).c_str());
106 107
	// make a copy of the msgsip when the SipEvent is copy-constructed
	mMsgSip = make_shared<MsgSip>(*sipEvent.mMsgSip);
108
}
Yann Diorcet's avatar
Yann Diorcet committed
109

110
SipEvent::~SipEvent() {
111
	// LOGD("Destroy SipEvent %p", this);
112
}
113

114 115
void SipEvent::flushLog() {
	if (mEventLog) {
116
		mAgent->logEvent(shared_from_this());
117
		mEventLog.reset();
118 119 120
	}
}

121 122 123
void SipEvent::setEventLog(const std::shared_ptr<EventLog> &log) {
	mEventLog = log;
	if (mState == TERMINATED) {
124 125 126 127
		flushLog();
	}
}

Yann Diorcet's avatar
Yann Diorcet committed
128
void SipEvent::terminateProcessing() {
129
	LOGD("Terminate SipEvent %p", this);
Yann Diorcet's avatar
Yann Diorcet committed
130 131
	if (mState == STARTED || mState == SUSPENDED) {
		mState = TERMINATED;
132
		flushLog();
133 134
		mIncomingAgent.reset();
		mOutgoingAgent.reset();
135
	} else if (mState == TERMINATED) {
Simon Morlat's avatar
Simon Morlat committed
136
		LOGE("SipEvent::terminateProcessing(): event is already terminated. Please fix your code.");
137
	} else {
138
		LOGA("Can't terminateProcessing: wrong state %s", stateStr(mState).c_str());
Yann Diorcet's avatar
Yann Diorcet committed
139 140 141 142
	}
}

void SipEvent::suspendProcessing() {
143
	LOGD("Suspend SipEvent %p", this);
Yann Diorcet's avatar
Yann Diorcet committed
144 145 146
	if (mState == STARTED) {
		mState = SUSPENDED;
	} else {
147
		LOGA("Can't suspendProcessing: wrong state %s", stateStr(mState).c_str());
Yann Diorcet's avatar
Yann Diorcet committed
148 149 150 151
	}
}

void SipEvent::restartProcessing() {
152
	LOGD("Restart SipEvent %p", this);
Yann Diorcet's avatar
Yann Diorcet committed
153 154 155
	if (mState == SUSPENDED) {
		mState = STARTED;
	} else {
156
		LOGA("Can't restartProcessing: wrong state %s", stateStr(mState).c_str());
Yann Diorcet's avatar
Yann Diorcet committed
157 158 159
	}
}

160
std::shared_ptr<IncomingTransaction> SipEvent::getIncomingTransaction() {
Simon Morlat's avatar
Simon Morlat committed
161 162 163
	return dynamic_pointer_cast<IncomingTransaction>(getIncomingAgent());
}

164
std::shared_ptr<OutgoingTransaction> SipEvent::getOutgoingTransaction() {
Simon Morlat's avatar
Simon Morlat committed
165 166 167
	return dynamic_pointer_cast<OutgoingTransaction>(getOutgoingAgent());
}

168
void RequestSipEvent::checkContentLength(const url_t *url) {
169
	sip_t *sip = mMsgSip->getSip();
170
	if (sip->sip_content_length == NULL) {
171
		string transport = ModuleToolbox::urlGetTransport(url);
172 173 174
		if (strcasecmp(transport.c_str(), "UDP") != 0) {
			/*if there is no Content-length and we are switching to a non-udp transport, we have to add a
			 * Content-Length, as requested by
175 176 177 178 179 180 181
			 * RFC3261 for reliable transports*/
			LOGD("Automatically adding content-length because going to a stream-based transport");
			sip->sip_content_length = sip_content_length_make(mMsgSip->getHome(), "0");
		}
	}
}

182 183 184 185
RequestSipEvent::RequestSipEvent(shared_ptr<IncomingAgent> incomingAgent, const shared_ptr<MsgSip> &msgSip,
								 tport_t *tport)
	: SipEvent(incomingAgent, msgSip), mRecordRouteAdded(false) {

186
	if (tport)
187
		mIncomingTport = shared_ptr<tport_t>(tport_ref(tport), tport_unref);
Yann Diorcet's avatar
Yann Diorcet committed
188 189
}

190 191
RequestSipEvent::RequestSipEvent(const shared_ptr<RequestSipEvent> &sipEvent)
	: SipEvent(*sipEvent), mRecordRouteAdded(sipEvent->mRecordRouteAdded), mIncomingTport(sipEvent->mIncomingTport) {
Yann Diorcet's avatar
Yann Diorcet committed
192 193
}

194 195
void RequestSipEvent::send(const shared_ptr<MsgSip> &msg, url_string_t const *u, tag_type_t tag, tag_value_t value,
						   ...) {
196
	if (mOutgoingAgent != NULL) {
197 198
		if (LOGD_ENABLED()){
			SLOGD << "Sending Request SIP message to " << (u ? url_as_string(msg->getHome(), (url_t const *)u) : "NULL")
199
			  << "\n" << *msg;
200
		}
201 202 203 204
		ta_list ta;
		ta_start(ta, tag, value);
		mOutgoingAgent->send(msg, u, ta_tags(ta));
		ta_end(ta);
205 206
	} else {
		LOGD("The Request SIP message is not send");
207 208
	}
	terminateProcessing();
Yann Diorcet's avatar
Yann Diorcet committed
209 210
}

211
void RequestSipEvent::reply(int status, char const *phrase, tag_type_t tag, tag_value_t value, ...) {
212
	if (mIncomingAgent != NULL) {
213
		SLOGD << "Replying Request SIP message: " << status << " " << phrase;
214 215
		ta_list ta;
		ta_start(ta, tag, value);
216
		mIncomingAgent->reply(getMsgSip(), status, phrase, ta_tags(ta));
217
		ta_end(ta);
218
	} else {
219
		SLOGD << "The Request SIP message is not replied";
220
	}
221 222
	if (status >= 200)
		terminateProcessing();
Yann Diorcet's avatar
Yann Diorcet committed
223
}
Yann Diorcet's avatar
Yann Diorcet committed
224

225
void RequestSipEvent::setIncomingAgent(const shared_ptr<IncomingAgent> &agent) {
226
	LOGA("Can't change incoming agent in request sip event");
Yann Diorcet's avatar
Yann Diorcet committed
227 228
}

229 230 231
shared_ptr<IncomingTransaction> RequestSipEvent::createIncomingTransaction() {
	shared_ptr<IncomingTransaction> transaction = dynamic_pointer_cast<IncomingTransaction>(mIncomingAgent);
	if (transaction == NULL) {
Simon Morlat's avatar
Simon Morlat committed
232
		transaction = IncomingTransaction::create(mIncomingAgent->getAgent());
233
		mIncomingAgent = transaction;
234 235

		transaction->handle(mMsgSip);
236
		linkTransactions();
237 238 239 240 241 242 243
	}
	return transaction;
}

shared_ptr<OutgoingTransaction> RequestSipEvent::createOutgoingTransaction() {
	shared_ptr<OutgoingTransaction> transaction = dynamic_pointer_cast<OutgoingTransaction>(mOutgoingAgent);
	if (transaction == NULL) {
Simon Morlat's avatar
Simon Morlat committed
244
		transaction = OutgoingTransaction::create(mOutgoingAgent->getAgent());
245
		mOutgoingAgent = transaction;
246
		linkTransactions();
247 248 249 250
	}
	return transaction;
}

251
void RequestSipEvent::linkTransactions() {
252 253
	shared_ptr<OutgoingTransaction> ot;
	shared_ptr<IncomingTransaction> it;
254 255 256 257 258

	if (mOutgoingAgent && mIncomingAgent && (ot = dynamic_pointer_cast<OutgoingTransaction>(mOutgoingAgent)) != NULL &&
		(it = dynamic_pointer_cast<IncomingTransaction>(mIncomingAgent)) != NULL) {
		ot->mIncoming = it;
		it->mOutgoing = ot;
259 260 261
	}
}

262
void RequestSipEvent::unlinkTransactions() {
263
	shared_ptr<OutgoingTransaction> ot;
264
	shared_ptr<IncomingTransaction> it;
265 266 267

	if (mOutgoingAgent && mIncomingAgent && (ot = dynamic_pointer_cast<OutgoingTransaction>(mOutgoingAgent)) != NULL &&
		(it = dynamic_pointer_cast<IncomingTransaction>(mIncomingAgent)) != NULL) {
Simon Morlat's avatar
Simon Morlat committed
268 269
		ot->mIncoming.reset();
		it->mOutgoing.reset();
270 271 272
	}
}

273 274 275
void RequestSipEvent::suspendProcessing() {
	SipEvent::suspendProcessing();

276 277 278 279
	if (getSip()->sip_request->rq_method != sip_method_ack) {//Currently does not make sens to create incoming transaction in case of ACK, specialy by forward module.
		// Become stateful if not already the case.
		createIncomingTransaction();
	}
280 281
}

282 283
RequestSipEvent::~RequestSipEvent() {
}
Yann Diorcet's avatar
Yann Diorcet committed
284

285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
bool RequestSipEvent::matchIncomingSubject(regex_t *regex){
	const su_strlst_t *strlst = tport_delivered_from_subjects(mIncomingTport.get(), mMsgSip->getMsg());
	int count = su_strlst_len(strlst);

	for (int k = 0 ; k < count ; ++k){
		const char *subj = su_strlst_item(strlst, k);
		LOGD("matchIncomingSubject %s", subj);
		int res = regexec(regex, subj, 0, NULL, 0);
		if (res == 0) {
			return true;
		}else if (res != REG_NOMATCH){
			LOGE("RequestSipEvent::matchIncomingSubject() regexec() returned unexpected %i", res);
		}
	}
	return false;
}

Ronan's avatar
Ronan committed
302
bool RequestSipEvent::findIncomingSubject(const char *searched) const {
303
	auto strlst = tport_delivered_from_subjects(mIncomingTport.get(), mMsgSip->getMsg());
304 305 306
	return !!tport_subject_search(searched, strlst);
}

Ronan's avatar
Ronan committed
307
const char *RequestSipEvent::findIncomingSubject(const list<string> &in) const {
308 309
	if (in.empty())
		return NULL;
310
	auto strlst = tport_delivered_from_subjects(mIncomingTport.get(), mMsgSip->getMsg());
311 312 313
	for (auto it = in.cbegin(); it != in.cend(); ++it) {
		if (tport_subject_search(it->c_str(), strlst))
			return it->c_str();
Guillaume Beraudo's avatar
Guillaume Beraudo committed
314 315 316 317
	}
	return NULL;
}

318 319 320
ResponseSipEvent::ResponseSipEvent(shared_ptr<OutgoingAgent> outgoingAgent, const shared_ptr<MsgSip> &msgSip)
	: SipEvent(outgoingAgent, msgSip), mPopVia(false) {
	mPopVia = mAgent != mOutgoingAgent.get(); // we pop the via if sending through transaction
Yann Diorcet's avatar
Yann Diorcet committed
321 322
}

323 324
ResponseSipEvent::ResponseSipEvent(const shared_ptr<ResponseSipEvent> &sipEvent)
	: SipEvent(*sipEvent), mPopVia(sipEvent->mPopVia) {
325 326
}

327 328 329 330
void ResponseSipEvent::checkContentLength(const shared_ptr<MsgSip> &msg, const sip_via_t *via) {
	if (msg->getSip()->sip_content_length == NULL && strcasecmp(via->v_protocol, "UDP") != 0) {
		/*if there is no Content-length and we are switching to a non-udp transport, we have to add a Content-Length, as
		 * requested by
331 332 333 334 335
			 * RFC3261 for reliable transports*/
		LOGD("Automatically adding content-length because going to a stream-based transport");
		msg->getSip()->sip_content_length = sip_content_length_make(mMsgSip->getHome(), "0");
	}
}
336

337 338
void ResponseSipEvent::send(const shared_ptr<MsgSip> &msg, url_string_t const *u, tag_type_t tag, tag_value_t value,
							...) {
339
	if (mIncomingAgent != NULL) {
340 341
		bool via_popped = false;
		if (mPopVia && msg == mMsgSip) {
342
			sip_via_remove(msg->getMsg(), msg->getSip());
343
			via_popped = true;
344
		}
345 346
		if (msg->getSip()->sip_via)
			checkContentLength(msg, msg->getSip()->sip_via);
347 348 349
		if (LOGD_ENABLED()){
			SLOGD << "Sending response:" << (via_popped ? " (via popped) " : "") << endl << *msg;
		}
350 351 352 353
		ta_list ta;
		ta_start(ta, tag, value);
		mIncomingAgent->send(msg, u, ta_tags(ta));
		ta_end(ta);
354
	} else {
355
		LOGD("The response is discarded.");
356 357
	}
	terminateProcessing();
358 359
}

360
void ResponseSipEvent::setOutgoingAgent(const shared_ptr<OutgoingAgent> &agent) {
361
	LOGA("Can't change outgoing agent in response sip event");
362 363
}

364
ResponseSipEvent::~ResponseSipEvent() {
Yann Diorcet's avatar
Yann Diorcet committed
365
}
366

367
std::ostream &operator<<(std::ostream &strm, const url_t &obj){
368 369 370 371
	SofiaAutoHome home;
	strm<<url_as_string(home.home(), &obj);
	return strm;
}
372 373

} // namespace flexisip