1 /**
2 * transaction.cpp
3 * Yet Another SIP Stack
4 * This file is part of the YATE Project http://YATE.null.ro
5 *
6 * Yet Another Telephony Engine - a fully featured software PBX and IVR
7 * Copyright (C) 2004-2014 Null Team
8 *
9 * This software is distributed under multiple licenses;
10 * see the COPYING file in the main directory for licensing
11 * information for this specific distribution.
12 *
13 * This use of this software may be subject to additional restrictions.
14 * See the LEGAL file in the main directory for details.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 */
20
21 #include <yatesip.h>
22
23 #include <string.h>
24 #include <stdlib.h>
25
26
27 using namespace TelEngine;
28
29 // Constructor from new message
SIPTransaction(SIPMessage * message,SIPEngine * engine,bool outgoing,bool * autoChangeParty)30 SIPTransaction::SIPTransaction(SIPMessage* message, SIPEngine* engine, bool outgoing,
31 bool* autoChangeParty)
32 : m_outgoing(outgoing), m_invite(false), m_transmit(false), m_state(Invalid),
33 m_response(0), m_timeouts(0), m_timeout(0),
34 m_firstMessage(message), m_lastMessage(0), m_pending(0), m_engine(engine), m_private(0),
35 m_autoChangeParty(autoChangeParty ? *autoChangeParty : engine->autoChangeParty()),
36 m_autoAck(true), m_silent(false)
37 {
38 DDebug(getEngine(),DebugAll,"SIPTransaction::SIPTransaction(%p,%p,%d) [%p]",
39 message,engine,outgoing,this);
40 if (m_firstMessage) {
41 m_firstMessage->ref();
42
43 const NamedString* ns = message->getParam("Via","branch",true);
44 if (ns)
45 m_branch = *ns;
46 if (!m_branch.startsWith("z9hG4bK"))
47 m_branch.clear();
48 ns = message->getParam("To","tag");
49 if (ns)
50 m_tag = *ns;
51
52 const MimeHeaderLine* hl = message->getHeader("Call-ID");
53 if (hl)
54 m_callid = *hl;
55
56 if (!m_outgoing && m_firstMessage->getParty()) {
57 // adjust the address where we send the answers
58 hl = message->getHeader("Via");
59 if (hl) {
60 URI uri(*hl);
61 // skip over protocol/version/transport
62 uri >> "/" >> "/" >> " ";
63 uri.trimBlanks();
64 uri = "sip:" + uri;
65 m_firstMessage->getParty()->setParty(uri);
66 }
67 }
68 }
69 m_invite = (getMethod() == YSTRING("INVITE"));
70 m_state = Initial;
71 m_transCount = outgoing ? m_engine->getReqTransCount() : m_engine->getRspTransCount();
72 if (!outgoing) {
73 m_engine->allocTraceId(m_traceId);
74 m_firstMessage->msgTraceId = m_traceId;
75 m_engine->traceMsg(m_firstMessage,true);
76 }
77 else
78 m_traceId = m_firstMessage->msgTraceId;
79 m_engine->append(this);
80 }
81
82 // Constructor from original and authentication requesting answer
SIPTransaction(SIPTransaction & original,SIPMessage * answer)83 SIPTransaction::SIPTransaction(SIPTransaction& original, SIPMessage* answer)
84 : m_outgoing(true), m_invite(original.m_invite), m_transmit(false), m_state(Process),
85 m_response(original.m_response), m_transCount(original.m_transCount),
86 m_timeouts(0), m_timeout(0),
87 m_firstMessage(original.m_firstMessage), m_lastMessage(original.m_lastMessage),
88 m_pending(0), m_engine(original.m_engine),
89 m_branch(original.m_branch), m_callid(original.m_callid), m_tag(original.m_tag),
90 m_private(0), m_autoChangeParty(original.m_autoChangeParty),
91 m_autoAck(original.m_autoAck), m_silent(original.m_silent), m_traceId(original.traceId())
92 {
93 DDebug(getEngine(),DebugAll,"SIPTransaction::SIPTransaction(&%p,%p) [%p]",
94 &original,answer,this);
95
96 SIPMessage* msg = new SIPMessage(*original.m_firstMessage);
97 MimeAuthLine* auth = answer->buildAuth(*original.m_firstMessage,m_engine);
98 m_firstMessage->setAutoAuth();
99 msg->complete(m_engine);
100 msg->addHeader(auth);
101 const NamedString* ns = msg->getParam("Via","branch",true);
102 if (ns)
103 original.m_branch = *ns;
104 else
105 original.m_branch.clear();
106 ns = msg->getParam("To","tag");
107 if (ns)
108 original.m_tag = *ns;
109 else
110 original.m_tag.clear();
111 original.m_firstMessage = msg;
112 original.m_lastMessage = 0;
113
114 #ifdef SIP_ACK_AFTER_NEW_INVITE
115 // if this transaction is an INVITE and we append it to the list its
116 // ACK will be sent after the new INVITE which is legal but "unnatural"
117 // some SIP endpoints seem to assume things about transactions
118 m_engine->append(this);
119 #else
120 // insert this transaction rather than appending it
121 // this way we get a chance to send one ACK before a new INVITE
122 // note that there is no guarantee because of the possibility of the
123 // packets getting lost and retransmitted or to use a different route
124 m_engine->insert(this);
125 #endif
126 }
127
128 // Constructor from original and forked dialog tag
SIPTransaction(const SIPTransaction & original,const String & tag)129 SIPTransaction::SIPTransaction(const SIPTransaction& original, const String& tag)
130 : m_outgoing(true), m_invite(original.m_invite), m_transmit(false), m_state(Process),
131 m_response(original.m_response), m_transCount(original.m_transCount),
132 m_timeouts(0), m_timeout(0),
133 m_firstMessage(original.m_firstMessage), m_lastMessage(0),
134 m_pending(0), m_engine(original.m_engine),
135 m_branch(original.m_branch), m_callid(original.m_callid), m_tag(tag),
136 m_private(0), m_autoChangeParty(original.m_autoChangeParty),
137 m_autoAck(original.m_autoAck), m_silent(original.m_silent), m_traceId(original.traceId())
138 {
139 if (m_firstMessage)
140 m_firstMessage->ref();
141
142 #ifdef SIP_PRESERVE_TRANSACTION_ORDER
143 // new transactions at the end, preserve "natural" order
144 m_engine->append(this);
145 #else
146 // put new transactions first - faster to match new messages
147 m_engine->insert(this);
148 #endif
149 }
150
~SIPTransaction()151 SIPTransaction::~SIPTransaction()
152 {
153 #ifdef DEBUG
154 Debugger debug(DebugAll,"SIPTransaction::~SIPTransaction()"," [%p]",this);
155 #endif
156 setPendingEvent(0,true);
157 TelEngine::destruct(m_lastMessage);
158 TelEngine::destruct(m_firstMessage);
159 }
160
destroyed()161 void SIPTransaction::destroyed()
162 {
163 DDebug(getEngine(),DebugAll,"SIPTransaction::destroyed() [%p]",this);
164 m_state = Invalid;
165 m_engine->remove(this);
166 setPendingEvent(0,true);
167 }
168
stateName(int state)169 const char* SIPTransaction::stateName(int state)
170 {
171 switch (state) {
172 case Invalid:
173 return "Invalid";
174 case Initial:
175 return "Initial";
176 case Trying:
177 return "Trying";
178 case Process:
179 return "Process";
180 case Retrans:
181 return "Retrans";
182 case Finish:
183 return "Finish";
184 case Cleared:
185 return "Cleared";
186 default:
187 return "Undefined";
188 }
189 }
190
changeState(int newstate)191 bool SIPTransaction::changeState(int newstate)
192 {
193 if ((newstate < 0) || (newstate == m_state))
194 return false;
195 if (m_state == Invalid) {
196 TraceDebugObj(this,getEngine(),DebugWarn,"SIPTransaction is already invalid [%p]",this);
197 return false;
198 }
199 DDebug(getEngine(),DebugAll,"SIPTransaction state changed from %s to %s [%p]",
200 stateName(m_state),stateName(newstate),this);
201 m_state = newstate;
202 return true;
203 }
204
setDialogTag(const char * tag)205 void SIPTransaction::setDialogTag(const char* tag)
206 {
207 if (null(tag)) {
208 if (m_tag.null())
209 m_tag = (int)Random::random();
210 }
211 else
212 m_tag = tag;
213 }
214
setLatestMessage(SIPMessage * message)215 void SIPTransaction::setLatestMessage(SIPMessage* message)
216 {
217 if (m_lastMessage == message)
218 return;
219 DDebug(getEngine(),DebugAll,"SIPTransaction latest message changing from %p %d to %p %d [%p]",
220 m_lastMessage, m_lastMessage ? m_lastMessage->code : 0,
221 message, message ? message->code : 0, this);
222 if (m_lastMessage)
223 m_lastMessage->deref();
224 m_lastMessage = message;
225 if (m_lastMessage) {
226 m_lastMessage->ref();
227 if (message->isAnswer()) {
228 m_response = message->code;
229 if ((m_response > 100) && ((m_response < 300)
230 || !(m_engine->flags() & SIPMessage::NoTagFailure)))
231 setDialogTag();
232 }
233 message->complete(m_engine,0,0,m_tag);
234 }
235 }
236
setPendingEvent(SIPEvent * event,bool replace)237 void SIPTransaction::setPendingEvent(SIPEvent* event, bool replace)
238 {
239 if (m_pending)
240 if (replace) {
241 delete m_pending;
242 m_pending = event;
243 }
244 else
245 delete event;
246 else
247 m_pending = event;
248 }
249
setTransCount(int count)250 void SIPTransaction::setTransCount(int count)
251 {
252 if (count < 0)
253 return;
254 else if (count < 2)
255 m_transCount = 2;
256 else if (count > 10)
257 m_transCount = 10;
258 else
259 m_transCount = count;
260 }
261
setTimeout(u_int64_t delay,unsigned int count)262 void SIPTransaction::setTimeout(u_int64_t delay, unsigned int count)
263 {
264 m_timeouts = count;
265 m_delay = delay;
266 m_timeout = (count && delay) ? Time::now() + delay : 0;
267 #ifdef DEBUG
268 if (m_timeout)
269 TraceDebugObj(this,getEngine(),DebugAll,"SIPTransaction new %d timeouts initially " FMT64U " usec apart [%p]",
270 m_timeouts,m_delay,this);
271 #endif
272 }
273
getEvent(bool pendingOnly,u_int64_t time)274 SIPEvent* SIPTransaction::getEvent(bool pendingOnly, u_int64_t time)
275 {
276 SIPEvent *e = 0;
277
278 if (m_pending) {
279 if (m_silent)
280 delete m_pending;
281 else
282 e = m_pending;
283 m_pending = 0;
284 return e;
285 }
286
287 if (m_transmit) {
288 m_transmit = false;
289 if (m_silent)
290 return 0;
291 return new SIPEvent(m_lastMessage ? m_lastMessage : m_firstMessage,this);
292 }
293
294 if (pendingOnly)
295 return 0;
296
297 int timeout = -1;
298 if (m_timeout) {
299 if (!time)
300 time = Time::now();
301 if (time >= m_timeout) {
302 timeout = --m_timeouts;
303 m_delay *= 2; // exponential back-off
304 m_timeout = (m_timeouts) ? time + m_delay : 0;
305 DDebug(getEngine(),DebugAll,"SIPTransaction fired timer #%d [%p]",timeout,this);
306 }
307 }
308
309 e = isOutgoing() ? getClientEvent(m_state,timeout) : getServerEvent(m_state,timeout);
310 if (e) {
311 if (!m_silent)
312 return e;
313 delete e;
314 return 0;
315 }
316
317 // do some common default processing
318 switch (m_state) {
319 case Retrans:
320 if (timeout < 0)
321 break;
322 if (timeout && m_lastMessage && !m_silent)
323 e = new SIPEvent(m_lastMessage,this);
324 // fall through because we recheck the timeout
325 case Finish:
326 if (timeout)
327 break;
328 changeState(Cleared);
329 // fall through so we don't wait another turn for processing
330 case Cleared:
331 setTimeout();
332 if (!m_silent)
333 e = new SIPEvent(m_firstMessage,this);
334 else
335 e = new SIPEvent(0,this);
336 // make sure we don't get trough this one again
337 changeState(Invalid);
338 return e;
339 case Invalid:
340 TraceDebugObj(this,getEngine(),DebugFail,"SIPTransaction::getEvent in invalid state [%p]",this);
341 break;
342 }
343 return e;
344 }
345
setResponse(SIPMessage * message)346 void SIPTransaction::setResponse(SIPMessage* message)
347 {
348 if (m_outgoing) {
349 TraceDebugObj(this,getEngine(),DebugWarn,"SIPTransaction::setResponse(%p) in client mode [%p]",message,this);
350 return;
351 }
352 Lock lock(m_engine);
353 setLatestMessage(message);
354 setTransmit();
355 if (message && (message->code >= 200)) {
356 if (isInvite()) {
357 // we need to actively retransmit this message
358 // RFC3261 17.2.1: non 2xx are not retransmitted on reliable transports
359 if (changeState(Retrans)) {
360 bool reliable = message->getParty() && message->getParty()->isReliable();
361 bool retrans = !reliable || message->code < 300;
362 setTimeout(m_engine->getTimer(retrans ? 'G' : 'H',reliable),
363 retrans ? getTransCount() : 1);
364 }
365 }
366 else {
367 // just wait and reply to retransmits
368 if (changeState(Finish))
369 setTimeout(m_engine->getTimer('J'));
370 }
371 }
372 // extend timeout for provisional messages, use proxy timeout (maximum)
373 else if (message && (message->code > 100))
374 setTimeout(m_engine->getTimer('C'));
375 }
376
setResponse() const377 bool SIPTransaction::setResponse() const
378 {
379 if (m_outgoing)
380 return false;
381 switch (m_state) {
382 case Initial:
383 case Trying:
384 case Process:
385 return true;
386 }
387 return false;
388 }
389
setResponse(int code,const char * reason)390 bool SIPTransaction::setResponse(int code, const char* reason)
391 {
392 if (m_outgoing) {
393 TraceDebugObj(this,getEngine(),DebugWarn,"SIPTransaction::setResponse(%d,'%s') in client mode [%p]",code,reason,this);
394 return false;
395 }
396 if (!setResponse()) {
397 DDebug(getEngine(),DebugInfo,"SIPTransaction ignoring setResponse(%d) in state %s [%p]",
398 code,stateName(m_state),this);
399 return false;
400 }
401 if (!reason)
402 reason = lookup(code,SIPResponses,"Unknown Reason Code");
403 SIPMessage* msg = new SIPMessage(m_firstMessage, code, reason);
404 setResponse(msg);
405 msg->deref();
406 return true;
407 }
408
setAcknowledge(MimeBody * ackBody)409 bool SIPTransaction::setAcknowledge(MimeBody* ackBody)
410 {
411 if (!(m_outgoing && m_lastMessage && m_lastMessage->isAnswer()
412 && ((Process == m_state) || (Retrans == m_state)))) {
413 TelEngine::destruct(ackBody);
414 return false;
415 }
416 m_autoAck = true;
417 // build and send the ACK
418 SIPMessage* m = new SIPMessage(m_firstMessage,m_lastMessage);
419 if (m_autoChangeParty && m_lastMessage->getParty())
420 m->setParty(m_lastMessage->getParty());
421 m->setBody(ackBody);
422 setLatestMessage(m);
423 m_lastMessage->deref();
424 setTransmit();
425 if (changeState(Finish)) {
426 setTimeout(m_engine->getTimer('H'));
427 return true;
428 }
429 return false;
430 }
431
requestAuth(const String & realm,const String & domain,bool stale,bool proxy)432 void SIPTransaction::requestAuth(const String& realm, const String& domain, bool stale, bool proxy)
433 {
434 if (m_outgoing) {
435 TraceDebugObj(this,getEngine(),DebugWarn,"SIPTransaction::requestAuth() in client mode [%p]",this);
436 return;
437 }
438 switch (m_state) {
439 case Invalid:
440 case Retrans:
441 case Finish:
442 case Cleared:
443 DDebug(getEngine(),DebugInfo,"SIPTransaction ignoring requestAuth() in state %s [%p]",
444 stateName(m_state),this);
445 return;
446 }
447 int code = proxy ? 407 : 401;
448 const char* hdr = proxy ? "Proxy-Authenticate" : "WWW-Authenticate";
449 SIPMessage* msg = new SIPMessage(m_firstMessage, code, lookup(code,SIPResponses));
450 if (realm) {
451 String tmp;
452 tmp << "Digest realm=" << MimeHeaderLine::quote(realm);
453 MimeHeaderLine* line = new MimeHeaderLine(hdr,tmp,',');
454 if (domain)
455 line->setParam(" domain",MimeHeaderLine::quote(domain));
456 m_engine->nonceGet(tmp);
457 line->setParam(" nonce",MimeHeaderLine::quote(tmp));
458 line->setParam(" stale",stale ? "TRUE" : "FALSE");
459 line->setParam(" algorithm","MD5");
460 msg->addHeader(line);
461 }
462 setResponse(msg);
463 msg->deref();
464 }
465
authUser(String & user,bool proxy,GenObject * userData)466 int SIPTransaction::authUser(String& user, bool proxy, GenObject* userData)
467 {
468 if (!(m_engine && m_firstMessage))
469 return -1;
470 return m_engine->authUser(m_firstMessage, user, proxy, userData);
471 }
472
processMessage(SIPMessage * message,const String & branch)473 SIPTransaction::Processed SIPTransaction::processMessage(SIPMessage* message, const String& branch)
474 {
475 if (!(message && m_firstMessage))
476 return NoMatch;
477 XDebug(getEngine(),DebugAll,"SIPTransaction::processMessage(%p,'%s') [%p]",
478 message,branch.c_str(),this);
479 if (branch) {
480 if (branch != m_branch) {
481 // different branch is allowed only for ACK in incoming INVITE...
482 if (!(isInvite() && isIncoming() && message->isACK()))
483 return NoMatch;
484 // ...and if also matches the CSeq, Call-ID and To: tag
485 if ((m_firstMessage->getCSeq() != message->getCSeq()) ||
486 (getCallID() != message->getHeaderValue("Call-ID")) ||
487 (getDialogTag() != message->getParamValue("To","tag")))
488 return NoMatch;
489 // ...and only if we sent a 200 response...
490 if (!m_lastMessage || ((m_lastMessage->code / 100) != 2))
491 #ifdef SIP_STRICT
492 return NoMatch;
493 #else
494 TraceDebugObj(this,getEngine(),DebugNote,"Received non-branch ACK to non-2xx response! (sender bug)");
495 #endif
496 DDebug(getEngine(),DebugAll,"SIPTransaction found non-branch ACK response to our 2xx");
497 }
498 else if (getMethod() != message->method) {
499 if (!(isIncoming() && isInvite() && message->isACK()))
500 return NoMatch;
501 if (!m_lastMessage || ((m_lastMessage->code / 100) == 2))
502 #ifdef SIP_STRICT
503 return NoMatch;
504 #else
505 TraceDebugObj(this,getEngine(),DebugNote,"Received branch ACK to 2xx response! (sender bug)");
506 #endif
507 }
508 }
509 else {
510 if (getMethod() != message->method) {
511 if (!(isIncoming() && isInvite() && message->isACK()))
512 return NoMatch;
513 }
514 if ((m_firstMessage->getCSeq() != message->getCSeq()) ||
515 (getCallID() != message->getHeaderValue("Call-ID")) ||
516 (m_firstMessage->getHeaderValue("From") != message->getHeaderValue("From")) ||
517 (m_firstMessage->getHeaderValue("To") != message->getHeaderValue("To")))
518 return NoMatch;
519 // allow braindamaged UAs that send answers with no Via line
520 if (m_firstMessage->getHeader("Via") && message->getHeader("Via") &&
521 (m_firstMessage->getHeaderValue("Via",true) != message->getHeaderValue("Via",true)))
522 return NoMatch;
523 // extra checks are to be made for ACK only
524 if (message->isACK()) {
525 if (getDialogTag() != message->getParamValue("To","tag"))
526 return NoMatch;
527 // use a while so we can either break or return
528 while (getURI() != message->uri) {
529 #ifndef SIP_STRICT
530 // hack to match URIs with lost tags. Cisco sucks. Period.
531 String tmp = getURI();
532 int sc = tmp.find(';');
533 if (sc > 0) {
534 tmp.assign(tmp,sc);
535 if (tmp == message->uri) {
536 TraceDebugObj(this,getEngine(),DebugMild,"Received no-branch ACK with lost URI tags! (sender bug)");
537 break;
538 }
539 }
540 // now try to match only the user part - Cisco strikes again...
541 sc = tmp.find('@');
542 if (sc > 0) {
543 tmp.assign(tmp,sc);
544 sc = message->uri.find('@');
545 if ((sc > 0) && (tmp == message->uri.substr(0,sc))) {
546 TraceDebugObj(this,getEngine(),DebugMild,"Received no-branch ACK with only user matching! (sender bug)");
547 break;
548 }
549 }
550 #endif
551 return NoMatch;
552 }
553 }
554 }
555 if (!message->getParty())
556 message->setParty(m_firstMessage->getParty());
557 if (isOutgoing() != message->isAnswer()) {
558 DDebug(getEngine(),DebugAll,"SIPTransaction ignoring retransmitted %s %p '%s' in [%p]",
559 message->isAnswer() ? "answer" : "request",
560 message,message->method.c_str(),this);
561 return NoMatch;
562 }
563 DDebug(getEngine(),DebugAll,"SIPTransaction processing %s %p '%s' %d in [%p]",
564 message->isAnswer() ? "answer" : "request",
565 message,message->method.c_str(),message->code,this);
566
567 if (message->isAnswer()) {
568 const NamedString* ns = message->getParam("To","tag");
569 if (m_tag.null()) {
570 if (ns) {
571 if (message->code > 100) {
572 // establish the dialog
573 m_tag = *ns;
574 DDebug(getEngine(),DebugInfo,"SIPTransaction found dialog tag '%s' [%p]",
575 m_tag.c_str(),this);
576 }
577 else
578 TraceDebugObj(this,getEngine(),DebugMild,"Received To tag in 100 answer! (sender bug)");
579 }
580 }
581 else if (!ns) {
582 // we have a dialog and the message has not - ignore it
583 // as we would be unable to CANCEL it anyway
584 return NoMatch;
585 }
586 else if (m_tag != *ns) {
587 // we have a dialog established and this message is out of it
588 if (!isInvite())
589 return NoMatch;
590 if (message->code < 400)
591 // for 1/2/3xx answers to INVITE discriminate forked for later processing
592 return NoDialog;
593 // we must answer any 4/5/6xx - and we're supposed to receive only one
594 DDebug(getEngine(),DebugInfo,"SIPTransaction changing dialog tag '%s' -> '%s' in %u answer [%p]",
595 m_tag.c_str(),ns->c_str(),message->code,this);
596 m_tag = *ns;
597 }
598 }
599
600 processMessage(message);
601 return Matched;
602 }
603
processMessage(SIPMessage * message)604 void SIPTransaction::processMessage(SIPMessage* message)
605 {
606 message->msgTraceId = m_traceId;
607 if (!message->isOutgoing())
608 getEngine()->traceMsg(message,true);
609 if (isOutgoing())
610 processClientMessage(message,m_state);
611 else
612 processServerMessage(message,m_state);
613 }
614
processClientMessage(SIPMessage * message,int state)615 void SIPTransaction::processClientMessage(SIPMessage* message, int state)
616 {
617 bool final = message->code >= 200;
618 switch (state) {
619 case Trying:
620 setTimeout(m_engine->getTimer(isInvite() ? 'B' : 'F'));
621 changeState(Process);
622 m_response = message->code;
623 if (m_response == 100)
624 break;
625 // fall trough for non-100 answers
626 case Process:
627 if (message->code <= 100)
628 break;
629 setLatestMessage(message);
630 if (tryAutoAuth(message))
631 break;
632 if (m_invite && !final)
633 // use the human interaction timeout in INVITEs
634 setTimeout(m_engine->getUserTimeout());
635 m_response = message->code;
636 setPendingEvent(new SIPEvent(message,this),final);
637 if (final) {
638 setTimeout();
639 if (isInvite()) {
640 if ((message->code / 100) != 2)
641 m_autoAck = true;
642 if (m_autoAck)
643 setAcknowledge();
644 else
645 changeState(Retrans);
646 }
647 else
648 changeState(Cleared);
649 }
650 break;
651 case Finish:
652 if (m_lastMessage && m_lastMessage->isACK() && final)
653 setTransmit();
654 break;
655 }
656 }
657
getClientEvent(int state,int timeout)658 SIPEvent* SIPTransaction::getClientEvent(int state, int timeout)
659 {
660 SIPEvent *e = 0;
661 switch (state) {
662 case Initial:
663 e = new SIPEvent(m_firstMessage,this);
664 if (changeState(Trying)) {
665 bool reliable = e->getParty() && e->getParty()->isReliable();
666 if (!reliable)
667 setTimeout(m_engine->getTimer(isInvite() ? 'A' : 'E'),getTransCount());
668 else
669 setTimeout(m_engine->getTimer(isInvite() ? 'B' : 'F',true),1);
670 }
671 break;
672 case Trying:
673 if (timeout < 0)
674 break;
675 if (timeout)
676 setTransmit();
677 else {
678 m_response = 408;
679 changeState(Cleared);
680 }
681 break;
682 case Process:
683 if (timeout == 0) {
684 m_response = 408;
685 changeState(Cleared);
686 }
687 break;
688 }
689 return e;
690 }
691
processServerMessage(SIPMessage * message,int state)692 void SIPTransaction::processServerMessage(SIPMessage* message, int state)
693 {
694 switch (state) {
695 case Trying:
696 case Process:
697 setTransmit();
698 break;
699 case Finish:
700 case Retrans:
701 if (message->isACK()) {
702 setTimeout();
703 setPendingEvent(new SIPEvent(message,this));
704 changeState(Cleared);
705 }
706 else
707 setTransmit();
708 break;
709 }
710 }
711
getServerEvent(int state,int timeout)712 SIPEvent* SIPTransaction::getServerEvent(int state, int timeout)
713 {
714 SIPEvent *e = 0;
715 switch (state) {
716 case Initial:
717 if (!( (m_firstMessage->getCSeq() >= 0) &&
718 m_firstMessage->getHeader("Call-ID") &&
719 m_firstMessage->getHeader("From") &&
720 m_firstMessage->getHeader("To") ))
721 setResponse(400);
722 else if (!m_engine->isAllowed(m_firstMessage->method))
723 setResponse(501);
724 else {
725 setResponse(100);
726 // if engine is set up lazy skip first 100 transmission
727 if (!isInvite() && m_engine && m_engine->lazyTrying())
728 m_transmit = false;
729 changeState(Trying);
730 break;
731 }
732 e = new SIPEvent(m_lastMessage,this);
733 m_transmit = false;
734 changeState(Invalid);
735 break;
736 case Trying:
737 e = new SIPEvent(m_firstMessage,this);
738 changeState(Process);
739 // the absolute maximum timeout as we have to accomodate proxies
740 setTimeout(m_engine->getTimer('C'));
741 break;
742 case Process:
743 if (timeout < 0)
744 break;
745 if (timeout && m_lastMessage)
746 e = new SIPEvent(m_lastMessage,this);
747 if (timeout)
748 break;
749 setResponse(408);
750 e = new SIPEvent(m_lastMessage,this);
751 break;
752 case Retrans:
753 if (isInvite() && (timeout == 0)) {
754 // we didn't got an ACK so declare timeout
755 m_response = 408;
756 changeState(Cleared);
757 }
758 break;
759 }
760 return e;
761 }
762
763 // Event transmission failed notification
msgTransmitFailed(SIPMessage * msg)764 void SIPTransaction::msgTransmitFailed(SIPMessage* msg)
765 {
766 if (!msg)
767 return;
768 Lock lock(getEngine());
769 DDebug(getEngine(),DebugNote,
770 "SIPTransaction send failed state=%s msg=%p first=%p last=%p [%p]",
771 stateName(m_state),msg,m_firstMessage,m_lastMessage,this);
772 // Do nothing in termination states
773 if (m_state == Invalid || m_state == Finish || m_state == Cleared)
774 return;
775 if (isOutgoing()) {
776 if (m_state == Trying) {
777 if (msg != m_firstMessage)
778 return;
779 // Reliable transport: terminate now
780 // Non reliable: terminate if this is the last attempt
781 if ((msg->getParty() && msg->getParty()->isReliable()) ||
782 m_timeouts >= getTransCount()) {
783 TraceDebugObj(this,getEngine(),DebugInfo,
784 "SIPTransaction send failed state=%s: clearing [%p]",
785 stateName(m_state),this);
786 m_response = 500;
787 changeState(Cleared);
788 return;
789 }
790 }
791 else if (m_state == Initial || msg != m_lastMessage)
792 return;
793 }
794 else {
795 // Incoming
796 if (msg != m_lastMessage)
797 return;
798 }
799 // Avoid party retry
800 TraceDebugObj(this,getEngine(),DebugAll,
801 "SIPTransaction send failed state=%s resetting msg %p party [%p]",
802 stateName(m_state),msg,this);
803 msg->setParty();
804 }
805
tryAutoAuth(SIPMessage * answer)806 bool SIPTransaction::tryAutoAuth(SIPMessage* answer)
807 {
808 if ((answer->code != 401) && (answer->code != 407))
809 return false;
810 if (m_firstMessage->getAuthUsername().null())
811 return false;
812 setTimeout();
813 SIPTransaction* tr = new SIPTransaction(*this,answer);
814 changeState(Initial);
815 tr->processClientMessage(answer,Process);
816 return true;
817 }
818
setSilent()819 void SIPTransaction::setSilent()
820 {
821 m_silent = true;
822 DDebug(getEngine(),DebugAll,"SIPTransaction silenced in state=%s [%p]",stateName(m_state),this);
823 }
824
825 /* vi: set ts=8 sw=4 sts=4 noet: */
826