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
28 #ifndef _AmSession_h_
29 #define _AmSession_h_
30
31 #include "AmRtpStream.h"
32 #include "AmThread.h"
33 #include "AmEventQueue.h"
34 #include "AmRtpAudio.h"
35 #include "AmDtmfDetector.h"
36 #include "AmSipMsg.h"
37 #include "AmSipHeaders.h"
38 #include "AmSipDialog.h"
39 #include "AmSipEvent.h"
40 #include "AmApi.h"
41 #include "AmSessionEventHandler.h"
42 #include "AmMediaProcessor.h"
43
44 #include "AmZRTP.h"
45
46 #include <string>
47 #include <vector>
48 #include <queue>
49 #include <map>
50 using std::string;
51 using std::vector;
52
53 class AmSessionFactory;
54 class AmDtmfEvent;
55
56 /** @file AmSession.h */
57
58 /* definition imported from Ser parser/msg_parser.h */
59 #define FL_FORCE_ACTIVE 2
60
61
62 /**
63 * \brief Implements the default behavior of one session
64 *
65 * The session is identified by Call-ID, From-Tag and To-Tag.
66 */
67 class AmSession :
68 public virtual AmObject,
69 #ifndef SESSION_THREADPOOL
70 public AmThread,
71 #endif
72 public AmEventQueue,
73 public AmEventHandler,
74 public AmSipDialogEventHandler,
75 public AmMediaSession,
76 public AmDtmfSink
77 {
78 AmMutex audio_mut;
79
80 protected:
81 vector<SdpPayload *> m_payloads;
82 //bool negotiate_onreply;
83
84 friend class AmRtpAudio;
85
86 /** get new RTP format for the session */
87 //virtual AmAudioRtpFormat* getNewRtpFormat();
88
89 private:
90 AmDtmfDetector m_dtmfDetector;
91 AmDtmfEventQueue m_dtmfEventQueue;
92 bool m_dtmfDetectionEnabled;
93
94 enum ProcessingStatus {
95 SESSION_PROCESSING_EVENTS = 0,
96 SESSION_WAITING_DISCONNECTED,
97 SESSION_ENDED_DISCONNECTED
98 };
99 ProcessingStatus processing_status;
100
101 #ifndef SESSION_THREADPOOL
102 /** @see AmThread::run() */
103 void run();
104 void on_stop();
105 #else
106 public:
107 void start();
108 bool is_stopped();
109
110 private:
111 void stop();
112 void* _pid;
113 #endif
114
115 static void session_started();
116 static void session_stopped();
117
118 static volatile unsigned int session_num;
119 static volatile unsigned int session_count;
120 static volatile unsigned int max_session_num;
121 static volatile unsigned long long avg_session_num;
122 static AmMutex session_num_mut;
123
124 friend class AmMediaProcessor;
125 friend class AmMediaProcessorThread;
126 friend class AmSessionContainer;
127 friend class AmSessionFactory;
128 friend class AmSessionProcessorThread;
129
130 std::unique_ptr<AmRtpAudio> _rtp_str;
131
132 /** Application parameters passed through P-App-Param HF */
133 map<string,string> app_params;
134
135 /** Sets the application parameters from the original request */
136 void setAppParams(const AmSipRequest& req);
137
138 protected:
139
140 AmCondition<bool> sess_stopped;
141
142 /** this is the group the media is processed with
143 - by default local tag */
144 string callgroup;
145
146 /** do accept early session? */
147 bool accept_early_session;
148
149 /** Local IP interface to be used for RTP streams */
150 int rtp_interface;
151
152 /** Session event handlers (ex: session timer, UAC auth, etc...) */
153 vector<AmSessionEventHandler*> ev_handlers;
154
155 AmAudio *input, *output;
156
157 virtual AmSipDialog* createSipDialog();
158
159 /** process pending events,
160 @return whether everything went smoothly */
161 virtual bool processEventsCatchExceptions();
162
163 /** @return whether startup was successful */
164 bool startup();
165
166 /** @return whether session continues running */
167 virtual bool processingCycle();
168
169 /** clean up session */
170 void finalize();
171
172 public:
173
174 enum SessionRefreshMethod {
175 REFRESH_REINVITE = 0, // use reinvite
176 REFRESH_UPDATE, // use update
177 REFRESH_UPDATE_FB_REINV // use update or fallback to reinvite
178 };
179 /** currently selected session refresh method */
180 SessionRefreshMethod refresh_method;
181
182 /** update selected session refresh method from remote capabilities */
183 void updateRefreshMethod(const string& headers);
184
185 AmRtpAudio* RTPStream();
hasRtpStream()186 bool hasRtpStream() { return _rtp_str.get() != NULL; }
187
188 string remote_rtp_mux_ip;
189 unsigned short remote_rtp_mux_port;
190
getRtpMuxRemoteIP()191 string getRtpMuxRemoteIP() { return remote_rtp_mux_ip; }
getRtpMuxRemotePort()192 unsigned short getRtpMuxRemotePort() { return remote_rtp_mux_port; }
193
194 #ifdef WITH_ZRTP
195 AmZRTPSessionState zrtp_session_state;
196
197 /** must be set before session is started! i.e. in constructor */
198 bool enable_zrtp;
199
200 #endif
201
202 AmSipDialog* dlg;
203
204 /**
205 * \brief Exception occured in a Session
206 *
207 * Session (creation) should be aborted and replied with code/reason.
208 */
209 struct Exception {
210 int code;
211 string reason;
212 string hdrs;
codeException213 Exception(int c, string r, string h="") : code(c), reason(r), hdrs(h) {}
214 };
215
216 /**
217 * Session constructor.
218 */
219 AmSession(AmSipDialog* dlg=NULL);
220
221 virtual ~AmSession();
222
223 /**
224 * @see AmEventHandler
225 */
226 virtual void process(AmEvent*);
227
228 /**
229 * add a handler which will be called
230 * for all events in session
231 *
232 * @see AmSessionEventHandler
233 */
234 void addHandler(AmSessionEventHandler*);
235
236 /* ---- media processing ---- */
237
238 /** start processing media - add to media processor */
239 void startMediaProcessing();
240
241 /** stop processing media - remove from media processor */
242 void stopMediaProcessing();
243
244 /**
245 * Set the call group for this call; calls in the same
246 * group are processed by the same media processor thread.
247 *
248 * Note: this must be set before inserting
249 * the session to the MediaProcessor!
250 */
251 void setCallgroup(const string& cg);
252
253 /** get the callgroup @return callgroup */
254 string getCallgroup();
255
256 /**
257 * change the callgroup
258 *
259 * This function removes the session from
260 * the media processor and adds it again.
261 */
262 void changeCallgroup(const string& cg);
263
264 /* ---- audio input and output ---- */
265
266 /**
267 * Lock audio input & output
268 * (inclusive RTP stream)
269 */
270 void lockAudio();
271
272 /**
273 * Unlock audio input & output
274 * (inclusive RTP stream)
275 */
276 void unlockAudio();
277
278 /**
279 * Audio input getter .
280 * Note: audio must be locked!
281 */
getInput()282 AmAudio* getInput() { return input; }
283 /**
284 * Audio output getter.
285 * Note: audio must be locked!
286 */
getOutput()287 AmAudio* getOutput() { return output; }
288
289 /**
290 * Audio input & output set methods.
291 * Note: audio will be locked by the methods.
292 */
293 void setInput(AmAudio* in);
294 void setOutput(AmAudio* out);
295 void setInOut(AmAudio* in, AmAudio* out);
296
297 /** checks if input/output is set, might be overidden! */
298 virtual bool isAudioSet();
299
300 /**
301 * Clears input & ouput (no need to lock)
302 */
303 virtual void clearAudio();
304
305 /** setter for rtp_str->mute */
setMute(bool mute)306 void setMute(bool mute) { RTPStream()->mute = mute; }
307
308 /** setter for rtp_str->receiving */
setReceiving(bool receive)309 void setReceiving(bool receive) { RTPStream()->setReceiving(receive); }
310
311 /** setter for rtp_str->force_receive_dtmf*/
setForceDtmfReceiving(bool receive)312 void setForceDtmfReceiving(bool receive) { RTPStream()->force_receive_dtmf = receive; }
313
314 /* ---- SIP dialog attributes ---- */
315
316 /** Gets the Session's call ID */
317 const string& getCallID() const;
318
319 /** Gets the Session's remote tag */
320 const string& getRemoteTag()const ;
321
322 /** Gets the Session's local tag */
323 const string& getLocalTag() const;
324
325 /** Gets the branch param of the first via in the original INVITE*/
326 const string& getFirstBranch() const;
327
328 /** Sets the Session's local tag if not set already */
329 void setLocalTag();
330
331 /** Sets the Session's local tag */
332 void setLocalTag(const string& tag);
333
334 /** Sets the URI for the session */
335 void setUri(const string& uri);
336
337 /* ---- RTP stream attributes ---- */
338
339 /** Gets the current RTP payload */
340 const vector<SdpPayload*>& getPayloads();
341
342 /** Gets the port number of the remote part of the session */
343 int getRPort();
344
345 /* ---- Call control ---- */
346
347 /** refresh the session - re-INVITE or UPDATE*/
348 virtual bool refresh(int flags = 0);
349
350 /** send an UPDATE in the session */
351 virtual int sendUpdate(const AmMimeBody* body, const string &hdrs);
352
353 /** send a Re-INVITE (if connected) */
354 virtual int sendReinvite(bool updateSDP = true, const string& headers = "",
355 int flags = 0);
356
357 /** send an INVITE */
358 virtual int sendInvite(const string& headers = "");
359
360 /** set the session on/off hold */
361 virtual void setOnHold(bool hold);
362
363 /** request the remote end to set the session on/off hold */
364 virtual void setRemoteHold(bool remote_hold);
365
366 /** update UAC trans state reference from old_cseq to new_cseq
367 e.g. if uac_auth or session_timer have resent a UAC request
368 */
updateUACTransCSeq(unsigned int old_cseq,unsigned int new_cseq)369 virtual void updateUACTransCSeq(unsigned int old_cseq, unsigned int new_cseq) { }
370
371 /* ---- Householding ---- */
372
373 /**
374 * Get a session parameter ('P-App-Param' HF, etc...)
375 */
376 string getAppParam(const string& param_name) const;
377
378 /**
379 * Destroy the session.
380 * It causes the session to be erased from the active session list
381 * and added to the dead session list.
382 * @see AmSessionContainer
383 */
384 virtual void destroy();
385
386 /**
387 * Signals the session it should stop.
388 * This will cause the session to be able
389 * to exit the main loop.
390 * If wakeup is set, a bogus event will
391 * be sent to wake up the session.
392 */
393 virtual void setStopped(bool wakeup = false);
394
395 /**
396 * Has the session already been stopped ?
397 */
getStopped()398 bool getStopped() { return sess_stopped.get(); }
399
400 /* ---- Statistics ---- */
401 /**
402 * Gets the number of running sessions
403 */
404 static unsigned int getSessionNum();
405 /**
406 * Gets the number of sessions since last startup
407 */
408 static unsigned int getSessionCount();
409 /**
410 * Gets the maximum of running sessions since last query
411 */
412 static unsigned int getMaxSessionNum();
413 /**
414 * Gets the average of running sessions since last query
415 */
416 static unsigned int getAvgSessionNum();
417
418 /* ---- DTMF ---- */
419 /**
420 * Entry point for DTMF events
421 */
422 void postDtmfEvent(AmDtmfEvent *);
423
424 void setInbandDetector(Dtmf::InbandDetectorType t);
isDtmfDetectionEnabled()425 bool isDtmfDetectionEnabled() { return m_dtmfDetectionEnabled; }
setDtmfDetectionEnabled(bool e)426 void setDtmfDetectionEnabled(bool e) { m_dtmfDetectionEnabled = e; }
427 void putDtmfAudio(const unsigned char *buf, int size, unsigned long long system_ts);
428
429 /**
430 * send a DTMF as RTP payload (RFC4733)
431 * @param event event ID (e.g. key press), see rfc
432 * @param duration_ms duration in milliseconds
433 */
434 void sendDtmf(int event, unsigned int duration_ms);
435
436 /* ---- general purpose application level timers ------------ */
437
438 /** Deprecated: check for support of timers
439 @return always true
440 */
441 static bool timersSupported();
442
443 /**
444 set a Timer
445 @param timer_id the ID of the timer (<0 for system timers)
446 @param timeout timeout in seconds (fractal value allowed)
447 @return true on success
448 */
449 virtual bool setTimer(int timer_id, double timeout);
450
451 /**
452 remove a Timer
453 @param timer_id the ID of the timer (<0 for system timers)
454 @return true on success
455 */
456 virtual bool removeTimer(int timer_id);
457
458 /**
459 remove all Timers
460 @return true on success
461 Note: this doesn't clear timer events already in the
462 event queue
463 */
464 virtual bool removeTimers();
465
466 /* ---------- event handlers ------------------------- */
467
468 /** DTMF event handler for apps to use*/
469 virtual void onDtmf(int event, int duration);
470
471 /**
472 * onStart will be called before everything else.
473 */
onStart()474 virtual void onStart() {}
475
476 /**
477 * onStop will be called once session is marked to be stopped (called only
478 * once).
479 */
onStop()480 virtual void onStop() {}
481
482 /**
483 * onInvite will be called if an INVITE or re-INVITE
484 * has been received for the session.
485 */
486 virtual void onInvite(const AmSipRequest& req);
487
488 /**
489 * onOutgoingInvite will be called if an INVITE
490 * is sent in the session.
491 */
onOutgoingInvite(const string & headers)492 virtual void onOutgoingInvite(const string& headers) { }
493
494 /**
495 * onCancel will be called if a CANCEL for a running
496 * dialog has been received. At this point, the CANCEL
497 * transaction has been replied with 200.
498 *
499 * A normal plug-in does not have to do anything special,
500 * as normal dialogs are immediatly replied with 200
501 * or error code.
502 *
503 * Note: You are still responsible for responding the
504 * initial transaction.
505 */
506 virtual void onCancel(const AmSipRequest& req);
507
508 /**
509 * onRinging will be called after 180 is received.
510 * If local audio is set up, session is added to media processor.
511 */
onRinging(const AmSipReply & reply)512 virtual void onRinging(const AmSipReply& reply) {}
513
514 /**
515 * onBye is called whenever a BYE request is received.
516 */
517 virtual void onBye(const AmSipRequest& req);
518
519 /** remote side is unreachable - 408/481 reply received */
520 virtual void onRemoteDisappeared(const AmSipReply&);
521
522 /** Entry point for SIP Requests */
523 virtual void onSipRequest(const AmSipRequest& req);
524
525 /** Entry point for SIP Replies */
526 virtual void onSipReply(const AmSipRequest& req, const AmSipReply& reply,
527 AmBasicSipDialog::Status old_dlg_status);
528
529 /** 2xx reply has been received for an INVITE transaction */
530 virtual void onInvite2xx(const AmSipReply& reply);
531
532 virtual void onInvite1xxRel(const AmSipReply &);
533
534 /** answer for a locally sent PRACK is received */
535 virtual void onPrack2xx(const AmSipReply &);
536
537 virtual void onFailure();
538
539 virtual void onNoAck(unsigned int cseq);
540 virtual void onNoPrack(const AmSipRequest &req, const AmSipReply &rpl);
541
542 /**
543 * Entry point for Audio events
544 */
545 virtual void onAudioEvent(AmAudioEvent* audio_ev);
546
547 /**
548 * entry point for system events
549 */
550 virtual void onSystemEvent(AmSystemEvent* ev);
551
552 #ifdef WITH_ZRTP
553 /**
554 * ZRTP events @see ZRTP
555 */
556 virtual void onZRTPProtocolEvent(zrtp_protocol_event_t event, zrtp_stream_t *stream_ctx);
557 virtual void onZRTPSecurityEvent(zrtp_security_event_t event, zrtp_stream_t *stream_ctx);
558 #endif
559
560 /** This callback is called if RTP timeout encountered */
561 virtual void onRtpTimeout();
562
563 /** This callback is called if session
564 timeout encountered (session timers) */
565 virtual void onSessionTimeout();
566
567 /* Called by AmSipDialog when a request is sent */
568 virtual void onSendRequest(AmSipRequest& req, int& flags);
569
570 /** Called by AmSipDialog when a reply is sent */
571 virtual void onSendReply(const AmSipRequest& req, AmSipReply& reply, int& flags);
572
573 /** Hook called when an SDP offer is required */
574 virtual bool getSdpOffer(AmSdp& offer);
575
576 /** Hook called when an SDP offer is required */
577 virtual bool getSdpAnswer(const AmSdp& offer, AmSdp& answer);
578
579 /** Hook called when an SDP OA transaction has been completed */
580 virtual int onSdpCompleted(const AmSdp& offer, const AmSdp& answer);
581
582 /** Hook called when an early session starts (SDP OA completed + dialog in early state) */
583 virtual void onEarlySessionStart();
584
585 /** Hook called when the session creation is completed (INV trans replied with 200) */
586 virtual void onSessionStart();
587
588 /**
589 * called in the session thread before the session is destroyed,
590 * i.e. after the main event loop has finished
591 */
onBeforeDestroy()592 virtual void onBeforeDestroy() { }
593
594 // The IP address to put as c= in SDP bodies
595 string advertisedIP(int addrType = AT_NONE);
596
597 // IP address used to bind the RTP socket
598 string localMediaIP(int addrType = AT_NONE);
599
600 /** format session id for debugging */
601 string sid4dbg();
602
603 /**
604 * Creates a new Id which can be used within sessions.
605 */
606 static string getNewId();
607
608 /* ----------------- media processing interface ------------------- */
609
610 public:
611 virtual int readStreams(unsigned long long ts, unsigned char *buffer);
612 virtual int writeStreams(unsigned long long ts, unsigned char *buffer);
clearRTPTimeout()613 virtual void clearRTPTimeout() { RTPStream()->clearRTPTimeout(); }
614 virtual void processDtmfEvents();
615
616 /**
617 * Call-backs used by RTP stream(s)
618 *
619 * Note: these methods will be called from the RTP receiver thread.
620 */
onBeforeRTPRelay(AmRtpPacket * p,sockaddr_storage * remote_addr)621 virtual bool onBeforeRTPRelay(AmRtpPacket* p, sockaddr_storage* remote_addr)
622 { return true; }
623
onAfterRTPRelay(AmRtpPacket * p,sockaddr_storage * remote_addr)624 virtual void onAfterRTPRelay(AmRtpPacket* p, sockaddr_storage* remote_addr) {}
625
626 int getRtpInterface();
627 void setRtpInterface(int _rtp_interface);
628 };
629
RTPStream()630 inline AmRtpAudio* AmSession::RTPStream() {
631 if (NULL == _rtp_str.get()) {
632 DBG("creating RTP stream instance for session [%p]\n",
633 this);
634 _rtp_str.reset(new AmRtpAudio(this,rtp_interface));
635 }
636 return _rtp_str.get();
637 }
638
639
640 #endif
641
642 /** EMACS **
643 * Local variables:
644 * mode: c++
645 * c-basic-offset: 2
646 * End:
647 */
648
649