1 /* 2 * Copyright (C) 2002-2003 Fhg Fokus 3 * 4 * This file is part of SEMS, a free SIP media server. 5 * 6 * SEMS is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. This program is released under 10 * the GPL with the additional exemption that compiling, linking, 11 * and/or using OpenSSL is allowed. 12 * 13 * For a license to use the SEMS software under conditions 14 * other than those described here, or to purchase support for this 15 * software, please contact iptel.org by e-mail at the following addresses: 16 * info@iptel.org 17 * 18 * SEMS is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU General Public License for more details. 22 * 23 * You should have received a copy of the GNU General Public License 24 * along with this program; if not, write to the Free Software 25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 26 */ 27 /** @file AmB2BSession.h */ 28 #ifndef AmB2BSession_h 29 #define AmB2BSession_h 30 31 #include "AmSession.h" 32 #include "AmSipDialog.h" 33 #include "sip/hash.h" 34 #include "AmB2BMedia.h" 35 #include "AmSipSubscription.h" 36 37 #define MAX_RELAY_STREAMS 3 // voice, video, rtt 38 39 enum { B2BTerminateLeg, 40 B2BConnectLeg, 41 B2BSipRequest, 42 B2BSipReply, 43 B2BMsgBody }; 44 45 /** \brief base class for event in B2B session */ 46 struct B2BEvent: public AmEvent 47 { 48 enum B2BEventType { 49 B2BCore, 50 B2BApplication, 51 } ev_type; 52 53 map<string, string> params; 54 B2BEventB2BEvent55 B2BEvent(int ev_id) 56 : AmEvent(ev_id), ev_type(B2BCore) 57 {} 58 B2BEventB2BEvent59 B2BEvent(int ev_id, B2BEventType ev_type) 60 : AmEvent(ev_id), ev_type(ev_type) 61 { } 62 B2BEventB2BEvent63 B2BEvent(int ev_id, B2BEventType ev_type, map<string, string> params) 64 : AmEvent(ev_id), ev_type(ev_type), params(params) 65 { } 66 }; 67 68 /** \brief base class for SIP event in B2B session */ 69 struct B2BSipEvent: public B2BEvent 70 { 71 bool forward; 72 B2BSipEventB2BSipEvent73 B2BSipEvent(int ev_id, bool forward) 74 : B2BEvent(ev_id), 75 forward(forward) 76 {} 77 }; 78 79 /** \brief SIP request in B2B session */ 80 struct B2BSipRequestEvent: public B2BSipEvent 81 { 82 AmSipRequest req; 83 B2BSipRequestEventB2BSipRequestEvent84 B2BSipRequestEvent(const AmSipRequest& req, bool forward) 85 : B2BSipEvent(B2BSipRequest,forward), 86 req(req) 87 { } 88 }; 89 90 /** \brief SIP reply in B2B session */ 91 struct B2BSipReplyEvent: public B2BSipEvent 92 { 93 AmSipReply reply; 94 string trans_method; 95 string sender_ltag; 96 B2BSipReplyEventB2BSipReplyEvent97 B2BSipReplyEvent(const AmSipReply& reply, bool forward, 98 string trans_method, string sender_ltag) 99 : B2BSipEvent(B2BSipReply,forward), 100 reply(reply), trans_method(trans_method), sender_ltag(sender_ltag) 101 { } 102 }; 103 104 /** \brief trigger connecting the callee leg in B2B session */ 105 struct B2BConnectEvent: public B2BEvent 106 { 107 string remote_party; 108 string remote_uri; 109 110 AmMimeBody body; 111 string hdrs; 112 113 bool relayed_invite; 114 unsigned int r_cseq; 115 B2BConnectEventB2BConnectEvent116 B2BConnectEvent(const string& remote_party, 117 const string& remote_uri) 118 : B2BEvent(B2BConnectLeg), 119 remote_party(remote_party), 120 remote_uri(remote_uri), 121 relayed_invite(false), 122 r_cseq(0) 123 {} 124 }; 125 126 /** 127 * \brief Base class for Sessions in B2BUA mode. 128 * 129 * It has two legs as independent sessions: 130 * Callee- and caller-leg. 131 */ 132 class AmB2BSession: public AmSession, protected RelayController 133 { 134 public: 135 136 enum RTPRelayMode { 137 /* audio will go directly between caller and callee 138 * SDP bodies of relayed requests are filtered */ 139 RTP_Direct, 140 141 /* audio will be realyed through us 142 * SDP bodies of relayed requests are filtered 143 * and connection addresses are replaced by us 144 */ 145 RTP_Relay, 146 147 /* 148 * similar to RTP_Relay, but additionally transcoding 149 * might be used depending on payload IDs 150 */ 151 RTP_Transcoding 152 }; 153 154 private: 155 /** local tag of the other leg */ 156 string other_id; 157 158 /** CSeq map for REFER subscriptions */ 159 map<unsigned int, unsigned int> refer_id_map; 160 161 protected: 162 /** Tell if the session should 163 * process SIP request itself 164 * or only relay them (B2B mode). 165 */ 166 bool sip_relay_only; 167 168 bool a_leg; 169 170 /** 171 * Requests which have been relayed 172 * from the other leg and sent as SIP 173 */ 174 TransMap relayed_req; 175 176 /** Requests received for relaying */ 177 TransMap recvd_req; 178 179 /** CSeq and Max-Forwards of the INVITE that established this call */ 180 unsigned int est_invite_cseq; 181 unsigned int est_invite_other_cseq; 182 unsigned int est_invite_max_forwards; 183 184 /** SUBSCRIBE/NOTIFY handling */ 185 AmSipSubscription* subs; 186 187 /** body of established session */ 188 AmMimeBody established_body; 189 /** hash of body (from o-line) */ 190 uint32_t body_hash; 191 /** save current session description (SDP) */ 192 virtual bool saveSessionDescription(const AmMimeBody& body); 193 /** @return whether session description (SDP) has changed */ 194 virtual bool updateSessionDescription(const AmMimeBody& body); 195 196 /** reset relation with other leg */ 197 virtual void clear_other(); 198 199 /** send a relayed SIP Request */ 200 int relaySip(const AmSipRequest& req); 201 202 /** send a relayed SIP Reply */ 203 int relaySip(const AmSipRequest& orig, const AmSipReply& reply); 204 205 public: 206 207 void relayError(const string &method, unsigned cseq, bool forward, int sip_code, const char *reason); 208 void relayError(const string &method, unsigned cseq, bool forward, int err_code); 209 210 protected: 211 /** Terminate our leg and forget the other. */ 212 virtual void terminateLeg(); 213 214 /** Terminate the other leg and forget it.*/ 215 virtual void terminateOtherLeg(); 216 217 218 /** @see AmSession */ 219 virtual void updateUACTransCSeq(unsigned int old_cseq, unsigned int new_cseq); 220 221 void onSipRequest(const AmSipRequest& req); 222 void onSipReply(const AmSipRequest& req, const AmSipReply& reply, 223 AmBasicSipDialog::Status old_dlg_status); 224 225 void onRequestSent(const AmSipRequest& req); 226 void onReplySent(const AmSipRequest& req, const AmSipReply& reply); 227 228 void onInvite2xx(const AmSipReply& reply); 229 230 int onSdpCompleted(const AmSdp& local_sdp, const AmSdp& remote_sdp); 231 232 void onRemoteDisappeared(const AmSipReply& reply); 233 234 void onRtpTimeout(); 235 void onSessionTimeout(); 236 void onNoAck(unsigned int cseq); 237 238 /** send re-INVITE with established session description 239 * @return 0 on success 240 */ 241 int sendEstablishedReInvite(); 242 243 /** do session refresh */ 244 bool refresh(int flags = 0); 245 246 /** @see AmEventQueue */ 247 void process(AmEvent* event); 248 249 /** @see AmEventQueue */ 250 void finalize(); 251 252 /** B2BEvent handler */ 253 virtual void onB2BEvent(B2BEvent* ev); 254 255 /** handle BYE on other leg 256 @return whether BYE is processed and should not be relayed via SIP 257 if true, the application must have handled the BYE 258 (i.e. sent 200 OK to the BYE using relayError()) 259 */ 260 virtual bool onOtherBye(const AmSipRequest& req); 261 262 /** 263 * Reply received from other leg has been replied 264 * @return true if reply was processed (should be absorbed) 265 * @return false if reply was not processed 266 */ 267 virtual bool onOtherReply(const AmSipReply& reply); 268 269 AmB2BSession(const string& other_local_tag = "", AmSipDialog* p_dlg=NULL, 270 AmSipSubscription* p_subs=NULL); 271 272 virtual ~AmB2BSession(); 273 274 /** flag to enable RTP relay mode */ 275 RTPRelayMode rtp_relay_mode; 276 /** force symmetric RTP */ 277 bool rtp_relay_force_symmetric_rtp; 278 /** transparent seqno for RTP relay */ 279 bool rtp_relay_transparent_seqno; 280 /** transparent SSRC for RTP relay */ 281 bool rtp_relay_transparent_ssrc; 282 /** If true, transcoded audio is injected into 283 the inband DTMF detector */ 284 bool enable_dtmf_transcoding; 285 /** filter RTP DTMF (2833 / 4733) packets */ 286 bool enable_dtmf_rtp_filtering; 287 /** detect DTMF through RTP DTMF (2833 / 4733) packets */ 288 bool enable_dtmf_rtp_detection; 289 290 /** Low fidelity payloads for which inband DTMF 291 transcoding should be used */ 292 vector<SdpPayload> lowfi_payloads; 293 294 /** clear our and the other side's RTP streams from RTPReceiver */ 295 void clearRtpReceiverRelay(); 296 /** update remote connection in relay_streams */ 297 void updateRelayStreams(const AmMimeBody& body, 298 AmSdp& parser_sdp); 299 300 /** replace connection with our address */ 301 void updateLocalBody(AmMimeBody& body); 302 303 /** Called when SDP relayed from other leg should be sent to the remote party. 304 * Default implementation updates connection address and ports. */ 305 virtual void updateLocalSdp(AmSdp &sdp); 306 307 /** 308 * Returns true and sets mapped_id if refer_id corresponds to an existing 309 * refer event subscription which has been relayed. 310 */ 311 bool getMappedReferID(unsigned int refer_id, unsigned int& mapped_id) const; 312 virtual void insertMappedReferID(unsigned int refer_id, unsigned int mapped_id); 313 314 public: 315 setOtherId(const string & n_other_id)316 virtual void setOtherId(const string& n_other_id) { 317 other_id = n_other_id; 318 } getOtherId()319 virtual const string& getOtherId() const { return other_id; } 320 321 /** Relay one event to the other side. @return 0 on success */ 322 virtual int relayEvent(AmEvent* ev); 323 324 void set_sip_relay_only(bool r); 325 326 /** set RTP relay mode (possibly initiaze by given INVITE) */ 327 virtual void setRtpRelayMode(RTPRelayMode mode); 328 329 /** link RTP streams of other_session to our streams */ getRtpRelayMode()330 RTPRelayMode getRtpRelayMode() const { return rtp_relay_mode; } getRtpRelayForceSymmetricRtp()331 bool getRtpRelayForceSymmetricRtp() const { return rtp_relay_force_symmetric_rtp; } getEnableDtmfTranscoding()332 bool getEnableDtmfTranscoding() const { return enable_dtmf_transcoding; } getEnableDtmfRtpFiltering()333 bool getEnableDtmfRtpFiltering() const { return enable_dtmf_rtp_filtering; } getEnableDtmfRtpDetection()334 bool getEnableDtmfRtpDetection() const { return enable_dtmf_rtp_detection; } 335 void getLowFiPLs(vector<SdpPayload>& lowfi_payloads) const; 336 337 virtual void setRtpInterface(int relay_interface); 338 virtual void setRtpRelayForceSymmetricRtp(bool force_symmetric); 339 void setRtpRelayTransparentSeqno(bool transparent); 340 void setRtpRelayTransparentSSRC(bool transparent); 341 342 void setEnableDtmfTranscoding(bool enable); 343 void setEnableDtmfRtpFiltering(bool enable); 344 void setEnableDtmfRtpDetection(bool enable); 345 void setLowFiPLs(const vector<SdpPayload>& lowfi_payloads); 346 getRtpRelayTransparentSeqno()347 bool getRtpRelayTransparentSeqno() { return rtp_relay_transparent_seqno; } getRtpRelayTransparentSSRC()348 bool getRtpRelayTransparentSSRC() { return rtp_relay_transparent_ssrc; } 349 350 /* -------------- media processing -------------- */ 351 352 private: 353 AmB2BMedia *media_session; 354 355 public: 356 virtual void setMediaSession(AmB2BMedia *new_session); getMediaSession()357 AmB2BMedia *getMediaSession() { return media_session; } 358 359 // see RelayController 360 virtual void computeRelayMask(const SdpMedia &m, bool &enable, PayloadMask &mask); 361 }; 362 363 class AmB2BCalleeSession; 364 365 /** \brief Caller leg of a B2B session */ 366 class AmB2BCallerSession: public AmB2BSession 367 { 368 public: 369 enum CalleeStatus { 370 None=0, 371 NoReply, 372 Ringing, 373 Connected 374 }; 375 376 private: 377 // Callee Status 378 CalleeStatus callee_status; 379 380 int reinviteCaller(const AmSipReply& callee_reply); 381 382 protected: 383 AmSipRequest invite_req; 384 virtual void createCalleeSession(); 385 int relayEvent(AmEvent* ev); 386 387 /** Tell if the session should 388 * relay early media SDPs to 389 * caller leg 390 */ 391 bool sip_relay_early_media_sdp; 392 393 public: 394 AmB2BCallerSession(); 395 virtual ~AmB2BCallerSession(); 396 getCalleeStatus()397 CalleeStatus getCalleeStatus() { return callee_status; } setCalleeStatus(CalleeStatus c)398 void setCalleeStatus(CalleeStatus c) { callee_status = c; } 399 400 virtual AmB2BCalleeSession* newCalleeSession(); 401 402 void connectCallee(const string& remote_party, 403 const string& remote_uri, 404 bool relayed_invite = false); 405 getOriginalRequest()406 const AmSipRequest& getOriginalRequest() { return invite_req; } 407 408 // @see AmSession 409 void onInvite(const AmSipRequest& req); 410 void onInvite2xx(const AmSipReply& reply); 411 void onCancel(const AmSipRequest& req); 412 void onBye(const AmSipRequest& req); 413 414 void onRemoteDisappeared(const AmSipReply& reply); 415 416 void onSystemEvent(AmSystemEvent* ev); 417 418 // @see AmB2BSession 419 void terminateLeg(); 420 void terminateOtherLeg(); 421 virtual void onB2BEvent(B2BEvent* ev); 422 getInviteReq()423 AmSipRequest* getInviteReq() { return &invite_req; } 424 425 void set_sip_relay_early_media_sdp(bool r); 426 427 /** initialize RTP relay mode, if rtp_relay_enabled 428 must be called *before* callee_session is started 429 */ 430 void initializeRTPRelay(AmB2BCalleeSession* callee_session); 431 }; 432 433 /** \brief Callee leg of a B2B session */ 434 class AmB2BCalleeSession: public AmB2BSession 435 { 436 public: 437 AmB2BCalleeSession(const string& other_local_tag); 438 AmB2BCalleeSession(const AmB2BCallerSession* caller); 439 440 virtual ~AmB2BCalleeSession(); 441 442 virtual void onB2BEvent(B2BEvent* ev); 443 }; 444 445 #endif 446