1 /* 2 * Copyright (C) 2012 Frafos GmbH 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 AmBasicSipDialog(AmBasicSipEventHandler * h)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 #ifndef _AmBasicSipDialog_h_ 28 #define _AmBasicSipDialog_h_ 29 30 #include "AmSipMsg.h" 31 #include "AmUriParser.h" 32 33 #include <string> 34 #include <vector> 35 #include <map> 36 using std::string; 37 38 // flags which may be used when sending request/reply 39 #define SIP_FLAGS_VERBATIM 1 // send request verbatim, 40 // i.e. modify as little as possible ~AmBasicSipDialog()41 42 #define SIP_FLAGS_NOAUTH 1<<1 // don't add authentication header 43 #define SIP_FLAGS_NOCONTACT 1<<2 // don't add contact 44 45 #define SIP_FLAGS_NOTAG 1<<3 // don't add to-tag in reply 46 47 #define SIP_FLAGS_NOBL 1<<4 // do not use destination blacklist 48 49 /** \brief SIP transaction representation */ 50 struct AmSipTransaction 51 { 52 string method; 53 unsigned int cseq; 54 trans_ticket tt; 55 56 AmSipTransaction(const string& method, unsigned int cseq, const trans_ticket& tt) 57 : method(method), 58 cseq(cseq), 59 tt(tt) 60 {} 61 62 AmSipTransaction() 63 {} 64 }; 65 66 typedef std::map<int,AmSipRequest> TransMap; getUACTransMethod(unsigned int t_cseq)67 68 class AmBasicSipEventHandler; 69 70 class msg_logger; 71 72 class AmBasicSipDialog 73 : public AmObject 74 { 75 public: getUACTransPending()76 enum Status { 77 Disconnected=0, 78 Trying, 79 Proceeding, 80 Cancelling, 81 Early, 82 Connected, 83 Disconnecting, 84 __max_Status 85 }; 86 87 private: 88 static const char* status2str[__max_Status]; getStatusStr(AmBasicSipDialog::Status st)89 90 protected: 91 Status status; 92 93 string callid; 94 95 string local_tag; 96 string ext_local_tag; getStatusStr()97 98 string remote_tag; 99 string first_branch; 100 101 string contact_params; // params in Contact-HF getContactHdr()102 AmUriParser contact; 103 104 string user; // local user 105 string domain; // local domain 106 107 string local_uri; // local uri 108 string remote_uri; // remote uri 109 110 string remote_party; // To/From 111 string local_party; // To/From 112 113 string remote_ua; // User-Agent/Server 114 115 string route; 116 117 string next_hop; 118 bool next_hop_1st_req; 119 bool patch_ruri_next_hop; 120 bool next_hop_fixed; 121 122 int outbound_interface; 123 124 TransMap uas_trans; 125 TransMap uac_trans; getContactUri()126 127 /** Dialog usages in the sense of RFC 5057 */ 128 unsigned int usages; 129 130 AmBasicSipEventHandler* hdl; 131 132 /** 133 * Message logger 134 */ 135 msg_logger* logger; 136 137 /** 138 * Executed for replies sent by a local UA, 139 * right before the reply is passed to the transaction layer. 140 */ 141 virtual int onTxReply(const AmSipRequest& req, AmSipReply& reply, int& flags); 142 143 /** 144 * Executed for requests sent by a local UA, 145 * right before the request is passed to the transaction layer. 146 */ 147 virtual int onTxRequest(AmSipRequest& req, int& flags); getRoute()148 149 /** 150 * Executed for replies sent by a local UA, 151 * after the reply has been successfuly sent. 152 */ 153 virtual void onReplyTxed(const AmSipRequest& req, const AmSipReply& reply); 154 155 /** 156 * Executed for requests sent by a local UA, 157 * after the request has been successfuly sent. 158 */ 159 virtual void onRequestTxed(const AmSipRequest& req); 160 161 /** 162 * Basic sanity check on received requests 163 * 164 * Note: At this point in the processing, 165 * the request has not been inserted yet 166 * into the uas_trans container. 167 * Thus, reply_error() should be used 168 * instead of reply() method. setOutboundInterface(int interface_id)169 * 170 * @return true to continue processing, false otherwise 171 */ 172 virtual bool onRxReqSanity(const AmSipRequest& req); 173 174 /** 175 * Executed from onRxRequest() to allow inherited classes 176 * to extend the basic behavior. 177 * getOutboundIf()178 * @return true to continue processing, false otherwise 179 */ 180 virtual bool onRxReqStatus(const AmSipRequest& req) { return true; } 181 182 /** 183 * Basic sanity check on received replies 184 * 185 * @return true to continue processing, false otherwise 186 */ 187 virtual bool onRxReplySanity(const AmSipReply& reply); 188 189 /** 190 * Executed from onRxReply() to allow inherited classes 191 * to extend the basic behavior (deletes the transaction on final reply). 192 * 193 * @return true to continue processing, false otherwise 194 */ 195 virtual bool onRxReplyStatus(const AmSipReply& reply); 196 197 /** 198 * Terminate pending UAS transactions 199 */ 200 virtual void termUasTrans(); 201 202 /** 203 * Terminate pending UAC transactions 204 */ 205 virtual void termUacTrans(); 206 207 public: 208 209 string outbound_proxy; 210 bool force_outbound_proxy; 211 212 bool nat_handling; 213 214 unsigned int cseq; // Local CSeq for next request 215 bool r_cseq_i; 216 unsigned int r_cseq; // last remote CSeq 217 218 AmBasicSipDialog(AmBasicSipEventHandler* h=NULL); 219 virtual ~AmBasicSipDialog(); 220 221 void setEventhandler(AmBasicSipEventHandler* h) { hdl = h; } 222 223 /** @return UAC request coresponding to cseq or NULL */ 224 AmSipRequest* getUACTrans(unsigned int t_cseq); 225 226 /** @return UAS request coresponding to cseq or NULL */ 227 AmSipRequest* getUASTrans(unsigned int t_cseq); 228 229 /** @return the method of the corresponding uac request */ 230 string getUACTransMethod(unsigned int t_cseq); 231 232 /** @return whether UAC transaction is pending */ 233 bool getUACTransPending(); 234 235 /** 236 * Getter/Setter basic dialog status 237 */ 238 Status getStatus() const { return status; } 239 virtual void setStatus(Status new_status); 240 241 virtual const char* getStatusStr(); 242 static const char* getStatusStr(Status st); 243 244 unsigned int getUsages() { return usages; } 245 void incUsages() { usages++; } 246 void decUsages() { usages--; } 247 248 const string& getCallid() const { return callid; } 249 virtual void setCallid(const string& n_callid) { callid = n_callid; } 250 251 const string& getLocalTag() const { return local_tag; } 252 virtual void setLocalTag(const string& n_tag) { local_tag = n_tag; } 253 254 const string& getRemoteTag() const { return remote_tag; } 255 virtual void setRemoteTag(const string& n_tag); 256 257 const string& get1stBranch() const { return first_branch; } 258 virtual void set1stBranch(const string& n_branch) 259 { first_branch = n_branch; } 260 261 const string& getExtLocalTag() const { return ext_local_tag; } 262 virtual void setExtLocalTag(const string& new_ext_tag) resetOutboundIf()263 { ext_local_tag = new_ext_tag; } 264 265 const string& getContactParams() const { return contact_params; } 266 virtual void setContactParams(const string& new_contact_params) 267 { contact_params = new_contact_params; } 268 269 const AmUriParser &getContact() const { return contact; } 270 virtual void setContact(const AmUriParser &new_contact) initFromLocalRequest(const AmSipRequest & req)271 { contact = new_contact; } 272 273 const string& getUser() const { return user; } 274 virtual void setUser(const string& new_user) 275 { user = new_user; } 276 277 const string& getDomain() const { return domain; } 278 virtual void setDomain(const string& new_domain) 279 { domain = new_domain; } 280 281 const string& getLocalUri() const { return local_uri; } 282 virtual void setLocalUri(const string& new_local_uri) 283 { local_uri = new_local_uri; } 284 onRxReqSanity(const AmSipRequest & req)285 const string& getRemoteUri() const { return remote_uri; } 286 virtual void setRemoteUri(const string& new_remote_uri) 287 { remote_uri = new_remote_uri; } 288 289 const string& getLocalParty() const { return local_party; } 290 virtual void setLocalParty(const string& new_local_party) 291 { local_party = new_local_party; } 292 293 const string& getRemoteParty() const { return remote_party; } 294 virtual void setRemoteParty(const string& new_remote_party) 295 { remote_party = new_remote_party; } 296 297 const string& getRemoteUA() const { return remote_ua; } 298 virtual void setRemoteUA(const string& new_remote_ua) 299 { remote_ua = new_remote_ua; } 300 301 const string& getRouteSet() const { return route; } 302 virtual void setRouteSet(const string& new_rs) 303 { route = new_rs; } 304 305 const string& getNextHop() const { return next_hop; } 306 virtual void setNextHop(const string& new_nh) 307 { next_hop = new_nh; } 308 309 bool getNextHop1stReq() const { return next_hop_1st_req; } 310 virtual void setNextHop1stReq(bool nh_1st_req) 311 { next_hop_1st_req = nh_1st_req; } 312 313 bool getPatchRURINextHop() const { return patch_ruri_next_hop; } 314 virtual void setPatchRURINextHop(bool patch_nh) 315 { patch_ruri_next_hop = patch_nh; } 316 317 bool getNextHopFixed() const { return next_hop_fixed; } 318 virtual void setNextHopFixed(bool nh_fixed) 319 { next_hop_fixed = nh_fixed; } 320 321 /** 322 * Compute the Contact-HF for the next request 323 */ onRxRequest(const AmSipRequest & req)324 string getContactHdr(); 325 326 /** 327 * Compute the Contact URI for the next request 328 */ 329 string getContactUri(); 330 331 /** 332 * Compute the Route-HF for the next request 333 */ 334 string getRoute(); 335 336 /** 337 * Set outbound_interface to specific value (-1 = default). 338 */ 339 virtual void setOutboundInterface(int interface_id); 340 341 /** 342 * Compute, set and return the outbound interface 343 * based on remote_uri, next_hop_ip, outbound_proxy, route. 344 */ 345 int getOutboundIf(); 346 347 /** 348 * Reset outbound_interface to default value (-1). 349 */ 350 void resetOutboundIf(); 351 352 /** 353 * Set outbound_interface to specific value (-1 = default). 354 */ 355 //void setOutboundInterface(int interface_id); 356 357 /** Initialize dialog from locally originated UAC request */ 358 virtual void initFromLocalRequest(const AmSipRequest& req); 359 360 /** 361 * Executed for requests received by the local UA. 362 */ 363 virtual void onRxRequest(const AmSipRequest& req); 364 365 /** 366 * Executed for replies received by the local UA. 367 */ 368 virtual void onRxReply(const AmSipReply& reply); 369 370 /** 371 * Updates remote_uri if necessary. 372 * 373 * Note: this method is offered for inherited classes 374 * implementing dialog functionnalities. It is 375 * not used by the basic class. 376 */ 377 void updateDialogTarget(const AmSipReply& reply); 378 379 /** @return 0 on success */ 380 virtual int reply(const AmSipRequest& req, 381 unsigned int code, 382 const string& reason, onRxReplyStatus(const AmSipReply & reply)383 const AmMimeBody* body = NULL, 384 const string& hdrs = "", 385 int flags = 0); 386 387 /** @return 0 on success */ 388 virtual int sendRequest(const string& method, 389 const AmMimeBody* body = NULL, 390 const string& hdrs = "", 391 int flags = 0, 392 int max_forwards = -1); 393 394 /** 395 * Terminates pending UAS/UAC transactions 396 */ 397 virtual void finalize() { 398 termUasTrans(); 399 termUacTrans(); 400 } 401 402 virtual void dropTransactions(); 403 404 /** 405 * This method should only be used to send responses 406 * to requests which are not referenced by any dialog. 407 * 408 * WARNING: If the request has already been referenced 409 * (see uas_trans), this method cannot mark the request 410 * as replied, thus leaving it in the pending state forever. termUasTrans()411 */ 412 static int reply_error(const AmSipRequest& req, 413 unsigned int code, 414 const string& reason, 415 const string& hdrs = "", 416 msg_logger* logger = NULL); 417 418 /* dump transaction information (DBG) */ 419 void dump(); 420 421 /** 422 * Enable or disable message logger 423 */ 424 void setMsgLogger(msg_logger* logger); 425 426 /** 427 * Get message logger termUacTrans()428 */ 429 msg_logger* getMsgLogger() { return logger; } 430 }; 431 432 /** 433 * \brief base class for SIP request/reply event handler 434 */ 435 class AmBasicSipEventHandler 436 { 437 public: 438 439 /** Hook called when a request has been received */ 440 virtual void onSipRequest(const AmSipRequest& req) {} 441 dropTransactions()442 /** Hook called when a reply has been received */ 443 virtual void onSipReply(const AmSipRequest& req, 444 const AmSipReply& reply, 445 AmBasicSipDialog::Status old_status) {} 446 onRxReplySanity(const AmSipReply & reply)447 /** Hook called before a request is sent */ 448 virtual void onSendRequest(AmSipRequest& req, int& flags) {} 449 450 /** Hook called before a reply is sent */ 451 virtual void onSendReply(const AmSipRequest& req, 452 AmSipReply& reply, int& flags) {} 453 454 /** Hook called after a request has been sent */ 455 virtual void onRequestSent(const AmSipRequest& req) {} 456 457 /** Hook called after a reply has been sent */ 458 virtual void onReplySent(const AmSipRequest& req, const AmSipReply& reply) {} 459 460 /** 461 * Hook called when the all dialog usages should be terminated 462 * after a reply received from the far end, or a locally generated 463 * timeout (408). 464 */ 465 virtual void onRemoteDisappeared(const AmSipReply& reply) {} 466 onRxReply(const AmSipReply & reply)467 /** 468 * Hook called when the all dialog usages should be terminated 469 * before a local reply is sent. 470 */ 471 virtual void onLocalTerminate(const AmSipReply& reply) {} 472 473 /** 474 * Hook called when either a received request or 475 * reply has been rejected by the local SIP UA layer. 476 */ 477 virtual void onFailure() {} 478 479 // called upon finishing either UAC or UAS transaction 480 virtual void onTransFinished() { } 481 482 483 virtual ~AmBasicSipEventHandler() {} 484 }; 485 486 #endif 487