/* * Copyright 2013, 2014 Range Networks, Inc. * * This software is distributed under multiple licenses; * see the COPYING file in the main directory for licensing * information for this specific distribution. * * This use of this software may be subject to additional restrictions. * See the LEGAL file in the main directory for details. 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. */ // Written by Pat Thompson. #ifndef SIPDIALOG_H #define SIPDIALOG_H #include #include #include #include "SIPExport.h" #include "SIPMessage.h" #include "SIPBase.h" #include "SIPRtp.h" #include "SIPTransaction.h" namespace SIP { class SipDialogBase: public virtual SipBase, public SipRtp { public: void sipWrite(SipMessage *sipmsg); SipDialog *dgGetDialog(); SipState MODSendCANCEL(Control::TermCause l3Cause); void initRTP(); void MOCInitRTP(); void MTCInitRTP(); string sdbText() const; void sdbText(std::ostringstream&os, bool verbose=false) const; string makeSDPOffer(); string makeSDPAnswer(); int vGetRtpPort() const { return this->SipRtp::mRTPPort; } Control::CodecSet vGetCodecs() const { return this->SipRtp::mCodec; } }; // Typical OpenBTS message stream for MOC to MTC on same BTS: // MOC invite-> // MOC <-100 // MTC <-invite // MTC 100-> // MTC 180-> // MOC <-180 // MTC 200-> // MTC <-ACK // MOC <-200 // CC Connect class SipInviteServerTransactionLayerBase: public SipTimers, public virtual SipDialogBase { public: virtual void dialogPushState(SipState newState, int code, char letter=0) = 0; // This is used by inbound BYE or CANCEL. We dont care which because both kill off the dialog. SipTimer mTimerJ; void setTimerJ() { if (!dsPeer()->ipIsReliableTransport()) { mTimerJ.setOnce(64 * T1); } } void SipMTBye(SipMessage *sipmsg); void SipMTCancel(SipMessage *sipmsg); }; // The SipStates used here and their correspondence to RFC3261 server transaction states are: // Our SipState | RFC3261 INVITE server | RFC3261 non-INVITE server // Starting | N/A | Trying // Proceeding | Proceeding | Proceeding // Connecting | TU sent OK, TL goes to state Terminated, but we go to Completed | N/A // Active | Confirmed | Completed // SSFail, various cancel/bye states class SipMTInviteServerTransactionLayer : public virtual SipInviteServerTransactionLayerBase { SipTimer mTimerG; // Resend response for unreliable transport. // TimerHJ is how long we wait for a response from the peer before declaring failure. // For non-INVITE it is TimerJ, and for INVITE it is timerH. // For INVITE it is the wait for additional requests to be answered with the previous response. // In RFC3261 the 200 OK reply is passed to the TU which needs a similar delay; but we are going to use the same // state machine to send the 200 OK response, which makes it look more similar to the non-INVITE server transaction (figure 8.) // After an ACK is received, TimerI is how long we will soak up additional ACKs, but who cares? We will soak // them up as long as the dialog is extant. SipTimer mTimerH; // There is no SIP specified timer for the 2xx response to an INVITE. // Eventually the MS will stop waiting and we will be canceled from that side. SipMessage mtLastResponse; void stopTimers() { mTimerG.stop(); mTimerH.stop(); /*mTimerI.stop();*/ } void setTimerG() { if (!dsPeer()->ipIsReliableTransport()) { mTimerG.setOnce(T1); } } void setTimerH() { if (!dsPeer()->ipIsReliableTransport()) { mTimerH.setOnce(64 * T1); } } protected: void mtWriteLowSide(SipMessage *sipmsg) { // Outgoing message. mtLastResponse = *sipmsg; sipWrite(sipmsg); } public: void MTCSendTrying(); void MTCSendRinging(); void MTCSendOK(CodecSet wCodec, const L3LogicalChannel *chan); // Doesnt seem like messages need the private headers. void MTSMSReply(int code, const char *explanation); // , const L3LogicalChannel *chan) void MTSMSSendTrying(); // This can only be used for early errors before we get the ACK. void MTCEarlyError(Control::TermCause cause); // The message must be 300-699. // This is called for the second and subsequent received INVITEs as well as the ACK. // We send the current response, whatever it is. void MTWriteHighSide(SipMessage *sipmsg); // Return TRUE to remove the dialog. bool mtPeriodicService(); string mttlText() const; // MT Transaction Layer Text }; class SipMOInviteClientTransactionLayer : public virtual SipInviteServerTransactionLayerBase { SipTimer mTimerAE; // Time to resend initial INVITE for non-reliable transport. SipTimer mTimerBF; // Timeout during INVITE phase. virtual void handleInviteResponse(int status, bool sendAck) = 0; void stopTimers() { mTimerAE.stop(); mTimerBF.stop(); mTimerK.stop(); mTimerD.stop(); } protected: // Timers K and D are for non-invite client transactions, MO BYE and MO CANCEL. SipTimer mTimerK; // Timeout destroys dialog. SipTimer mTimerD; // Timeout destroys dialog. void MOCSendINVITE(const L3LogicalChannel *chan = NULL); void MOUssdSendINVITE(string ussd, const L3LogicalChannel *chan = NULL); void handleSMSResponse(SipMessage *sipmsg); void MOWriteHighSide(SipMessage *sipmsg); // Incoming message from outside, called from SIPInterface. void moWriteLowSide(SipMessage *sipmsg); // Outgoing message from us, called only by SIPBase descendents. public: void MOCSendACK(); void MOSMSSendMESSAGE(const string &messageText, const string &contentType); bool moPeriodicService(); // Return TRUE to remove the dialog. string motlText() const; // MO Transaction Layer Text }; // MO, uses SIP Client transaction: // us -> INVITE -> them // us <- 1xx whatever <- them // us <- 200 OK <- them // us -> ACK -> them // We dont use server transactions for requests within an INVITE (RFC3261 section 17.2.2 Figure 8) // - the only thing the server transaction has to do is resend the reply if a new request arrives, // so that is just handled by the dialog. // For the INVITE server transaction (figure 7), the transaction layer is required to resend the 2xx // MT, uses SIP Server transaction: // us <- INVITE <- them duplicate INVITE handled by SIP2Interface, not SipServerTransaction // us -> 1xx whatever -> them // us -> 200 OK -> them // us <- ACK <- them // The antecedent classes are virtual because they all are descendents of a single SipBase. DEFINE_MEMORY_LEAK_DETECTOR_CLASS(SipDialog,MemCheckSipDialog) class SipDialog : public MemCheckSipDialog, public virtual SipDialogBase, public virtual SipMOInviteClientTransactionLayer, public virtual SipMTInviteServerTransactionLayer { private: // We only send one state change message to L3 for each change of DialogState. This is the previous one we sent. // There is no current dialog state - it is derived from SIPBase::mState DialogState::msgState mPrevDialogState; bool permittedTransition(DialogState::msgState oldState, DialogState::msgState newState); // Change the sip state and possibly push a message to L3. public: void dialogPushState(SipState newState, int code, char timer = 0); // Possibly send a message to L3 if the SIP state has changed. private: void dialogChangeState(SipMessage *dmsg); void registerHandleSipCode(SipMessage *msg); public: Bool_z mReceived180; // The 1xx response, with the caveat that 180 (ringing) is saved over others. // To work around the buggy smqueue we need to resend the SMS message so we need to save it. // There is another copy saved down in the transaction layer, but it is cleaner to just save it up here // than try to dig it out of the lower layer resend machinery. string smsBody, smsContentType; // Temporary, until smqueue is fixed. void dgReset(); DialogState::msgState getDialogState() const; bool isActive() const { return getDialogState() == DialogState::dialogActive; } bool isFinished() const { DialogState::msgState st = getDialogState(); return st == DialogState::dialogFail || st == DialogState::dialogBye; } bool dgIsDeletable() const; const char *dialogStateString() const { return DialogState::msgStateString(getDialogState()); } //void dialogOpen(const char *userid); // The userid is the IMSI. //void dialogClose(); void MODSendBYE(Control::TermCause l3Cause); void sendInfoDtmf(unsigned bcdkey); // Send an error code that terminates the dialog. void sendError(int code, const char *errorString) {LOG(ALERT) << "unimplemented"<