00001
00024 #ifndef __YATEJINGLE_H
00025 #define __YATEJINGLE_H
00026
00027 #include <yateclass.h>
00028 #include <yatejabber.h>
00029
00033 namespace TelEngine {
00034
00035 class JGRtpMedia;
00036 class JGCrypto;
00037 class JGRtpMediaList;
00038 class JGRtpCandidate;
00039 class JGRtpCandidates;
00040 class JGSessionContent;
00041 class JGStreamHost;
00042 class JGSession;
00043 class JGSession0;
00044 class JGSession1;
00045 class JGEvent;
00046 class JGEngine;
00047 class JGSentStanza;
00048
00049
00054 class YJINGLE_API JGRtpMedia : public GenObject
00055 {
00056 public:
00065 inline JGRtpMedia(const char* id, const char* name, const char* clockrate,
00066 const char* channels, const char* synonym)
00067 : m_params("")
00068 { set(id,name,clockrate,channels,synonym); }
00069
00074 inline JGRtpMedia(XMLElement* xml)
00075 : m_params("")
00076 { fromXML(xml); }
00077
00081 inline JGRtpMedia(const JGRtpMedia& src)
00082 : GenObject(),
00083 m_params(src.m_params)
00084 { set(src.m_id,src.m_name,src.m_clockrate,src.m_channels,src.m_synonym); }
00085
00094 inline void set(const char* id, const char* name, const char* clockrate,
00095 const char* channels, const char* synonym) {
00096 m_id = id;
00097 m_name = name;
00098 m_clockrate = clockrate;
00099 m_channels = channels;
00100 m_synonym = synonym;
00101 }
00102
00107 virtual const String& toString() const
00108 { return m_id; }
00109
00114 XMLElement* toXML() const;
00115
00120 void fromXML(XMLElement* xml);
00121
00125 String m_id;
00126
00130 String m_name;
00131
00135 String m_clockrate;
00136
00140 String m_channels;
00141
00145 String m_synonym;
00146
00150 NamedList m_params;
00151 };
00152
00158 class YJINGLE_API JGCrypto : public String
00159 {
00160 public:
00168 inline JGCrypto(const char* tag = "1", const char* suite = 0,
00169 const char* key = 0, const char* session = 0)
00170 : String(tag),
00171 m_suite(suite), m_keyParams(key), m_sessionParams(session)
00172 {}
00173
00178 inline JGCrypto(const XMLElement* xml)
00179 { fromXML(xml); }
00180
00185 XMLElement* toXML() const;
00186
00191 void fromXML(const XMLElement* xml);
00192
00193 String m_suite;
00194 String m_keyParams;
00195 String m_sessionParams;
00196 };
00197
00202 class YJINGLE_API JGRtpMediaList : public ObjList
00203 {
00204 public:
00208 enum Media {
00209 MediaMissing = -1,
00210 MediaUnknown = 0,
00211 Audio = 1,
00212 };
00213
00219 inline JGRtpMediaList(Media m = MediaMissing, bool cryptoMandatory = false)
00220 : m_media(m), m_cryptoMandatory(cryptoMandatory), m_ready(false)
00221 {}
00222
00227 inline Media media() const
00228 { return m_media; }
00229
00238 inline void add(const char* id, const char* name, const char* clockrate,
00239 const char* bitrate, const char* synonym)
00240 { append(new JGRtpMedia(id,name,clockrate,bitrate,synonym)); }
00241
00247 JGRtpMedia* findMedia(const String& id);
00248
00254 JGRtpMedia* findSynonym(const String& value) const;
00255
00261 XMLElement* toXML(bool telEvent = true) const;
00262
00267 void fromXML(XMLElement* xml);
00268
00276 bool createList(String& dest, bool synonym, const char* sep = ",");
00277
00281 static TokenDict s_media[];
00282
00286 Media m_media;
00287
00291 bool m_cryptoMandatory;
00292 ObjList m_cryptoLocal;
00293 ObjList m_cryptoRemote;
00294
00298 bool m_ready;
00299 };
00300
00301
00306 class JGRtpCandidate : public String
00307 {
00308 public:
00312 inline JGRtpCandidate(const char* id, const char* component = "1",
00313 unsigned int generation = 0, unsigned int net = 0, int prio = 0)
00314 : String(id),
00315 m_port(0), m_component(component), m_generation(generation),
00316 m_network(net), m_priority(prio), m_protocol("udp"), m_type("host")
00317 {}
00318
00324 inline JGRtpCandidate(XMLElement* xml, const JGRtpCandidates& container)
00325 { fromXml(xml,container); }
00326
00332 XMLElement* toXml(const JGRtpCandidates& container) const;
00333
00339 void fromXml(XMLElement* xml, const JGRtpCandidates& container);
00340
00341 String m_address;
00342 String m_port;
00343 String m_component;
00344 String m_generation;
00345 String m_network;
00346 String m_priority;
00347 String m_protocol;
00348 String m_type;
00349 };
00350
00351
00356 class YJINGLE_API JGRtpCandidates : public ObjList
00357 {
00358 public:
00362 enum Type {
00363 Unknown = -1,
00364 RtpIceUdp = 1,
00365 RtpRawUdp = 2,
00366 };
00367
00372 inline JGRtpCandidates(Type t = Unknown)
00373 : m_type(t)
00374 {}
00375
00380 inline const char* typeName() const
00381 { return typeName(m_type); }
00382
00386 inline void generateIceAuth() {
00387 generateIceToken(m_password,true);
00388 generateIceToken(m_ufrag,false);
00389 }
00390
00394 inline void generateOldIceAuth() {
00395 generateOldIceToken(m_password);
00396 generateOldIceToken(m_ufrag);
00397 }
00398
00404 JGRtpCandidate* findByComponent(unsigned int component);
00405
00412 XMLElement* toXML(bool addCandidates, bool addAuth) const;
00413
00418 void fromXML(XMLElement* element);
00419
00427 static void generateIceToken(String& dest, bool pwd, unsigned int max = 0);
00428
00433 static void generateOldIceToken(String& dest);
00434
00441 static inline const char* typeName(int t, const char* defVal = "unknown")
00442 { return TelEngine::lookup(t,s_type,defVal); }
00443
00447 static TokenDict s_type[];
00448
00449 Type m_type;
00450 String m_password;
00451 String m_ufrag;
00452 };
00453
00460 class YJINGLE_API JGSessionContent : public RefObject
00461 {
00462 public:
00466 enum Type {
00467 Unknown = -1,
00468 UnknownFileTransfer = -2,
00469 RtpIceUdp = 1,
00470 RtpRawUdp = 2,
00471 FileBSBOffer = 3,
00472 FileBSBRequest = 4,
00473 };
00474
00478 enum Senders {
00479 SendUnknown = 0,
00480 SendBoth = 1,
00481 SendInitiator = 2,
00482 SendResponder = 3
00483 };
00484
00488 enum Creator {
00489 CreatorUnknown = 0,
00490 CreatorInitiator = 1,
00491 CreatorResponder = 2
00492 };
00493
00502 JGSessionContent(Type t, const char* name, Senders senders,
00503 Creator creator, const char* disposition = 0);
00504
00509 inline Type type() const
00510 { return m_type; }
00511
00516 inline Senders senders() const
00517 { return m_senders; }
00518
00523 inline Creator creator() const
00524 { return m_creator; }
00525
00531 inline bool isValidAudio() const
00532 { return (m_rtpMedia.media() == JGRtpMediaList::Audio) && (0 != m_rtpMedia.skipNull()); }
00533
00537 virtual const String& toString() const
00538 { return m_name; }
00539
00545 inline bool isSession() const
00546 { return !m_disposition || m_disposition == "session"; }
00547
00552 inline bool isEarlyMedia() const
00553 { return m_disposition == "early-session"; }
00554
00558 inline void setEarlyMedia()
00559 { m_disposition = "early-session"; }
00560
00570 XMLElement* toXml(bool minimum, bool addDesc,
00571 bool addTrans, bool addCandidates, bool addAuth) const;
00572
00580 static JGSessionContent* fromXml(XMLElement* xml, XMPPError::Type& err,
00581 String& error);
00582
00586 static TokenDict s_senders[];
00587
00591 static TokenDict s_creator[];
00592
00596 JGRtpMediaList m_rtpMedia;
00597
00601 JGRtpCandidates m_rtpLocalCandidates;
00602
00606 JGRtpCandidates m_rtpRemoteCandidates;
00607
00611 NamedList m_fileTransfer;
00612
00613 private:
00614 Type m_type;
00615 String m_name;
00616 Senders m_senders;
00617 Creator m_creator;
00618 String m_disposition;
00619 };
00620
00621
00626 class JGStreamHost : public String
00627 {
00628 public:
00636 JGStreamHost(const char* jid, const char* addr, int port, const char* zeroConf = 0)
00637 : String(jid),
00638 m_address(addr), m_port(port), m_zeroConf(zeroConf)
00639 {}
00640
00645 inline JGStreamHost(const JGStreamHost& src)
00646 : String(src),
00647 m_address(src.m_address), m_port(src.m_port),
00648 m_zeroConf(src.m_zeroConf)
00649 {}
00650
00655 XMLElement* toXml();
00656
00662 static JGStreamHost* fromXml(XMLElement* xml);
00663
00671 static XMLElement* buildHosts(const ObjList& hosts, const char* sid,
00672 const char* mode = "tcp");
00673
00679 static XMLElement* buildRsp(const char* jid);
00680
00681 String m_address;
00682 int m_port;
00683 String m_zeroConf;
00684 };
00685
00686
00691 class YJINGLE_API JGSession : public RefObject, public Mutex
00692 {
00693 friend class JGEvent;
00694 friend class JGEngine;
00695 public:
00699 enum Version {
00700 Version0 = 0,
00701 Version1 = 1,
00702 VersionUnknown
00703 };
00704
00708 enum Reason {
00709 ReasonBusy,
00710 ReasonDecline,
00711 ReasonConn,
00712 ReasonMedia,
00713 ReasonTransport,
00714 ReasonNoError,
00715 ReasonOk,
00716 ReasonNoApp,
00717 ReasonAltSess,
00718 ReasonUnknown,
00719 ReasonTransfer,
00720 ReasonNone
00721 };
00722
00726 enum State {
00727 Idle = 0,
00728 Pending = 1,
00729 Active = 2,
00730 Ending = 3,
00731 Destroy = 4,
00732 };
00733
00737 enum Action {
00738 ActAccept,
00739 ActInitiate,
00740 ActTerminate,
00741 ActInfo,
00742 ActTransportInfo,
00743 ActTransportAccept,
00744 ActTransportReject,
00745 ActTransportReplace,
00746 ActContentAccept,
00747 ActContentAdd,
00748 ActContentModify,
00749 ActContentReject,
00750 ActContentRemove,
00751 ActContentInfo,
00752 ActTransfer,
00753 ActRinging,
00754 ActTrying,
00755 ActReceived,
00756 ActHold,
00757 ActActive,
00758 ActMute,
00759 ActDtmf,
00760 ActStreamHost,
00761 ActCount,
00762 };
00763
00767 virtual ~JGSession();
00768
00773 inline Version version() const
00774 { return m_version; }
00775
00780 inline bool outgoing() const
00781 { return m_outgoing; }
00782
00787 inline const String& sid() const
00788 { return m_sid; }
00789
00794 inline const JabberID& local() const
00795 { return m_localJID; }
00796
00801 inline const JabberID& remote() const
00802 { return m_remoteJID; }
00803
00808 inline State state() const
00809 { return m_state; }
00810
00815 inline const JBStream* stream() const
00816 { return m_stream; }
00817
00822 inline void* userData()
00823 { return m_private; }
00824
00829 inline void userData(void* userdata)
00830 { m_private = userdata; }
00831
00837 virtual XMLElement* checkJingle(XMLElement* xml)
00838 { return 0; }
00839
00845 inline Action getAction(XMLElement* xml)
00846 { return xml ? lookupAction(xml->getAttribute("type"),m_version) : ActCount; }
00847
00854 bool acceptEvent(JBEvent* event, const String& sid = String::empty());
00855
00866 bool confirm(XMLElement* xml, XMPPError::Type error = XMPPError::NoError,
00867 const char* text = 0, XMPPError::ErrorType type = XMPPError::TypeModify);
00868
00876 virtual bool accept(const ObjList& contents, String* stanzaId = 0)
00877 { return false; }
00878
00886 virtual bool hangup(int reason, const char* msg = 0);
00887
00892 virtual XMLElement* createHoldXml()
00893 { return 0; }
00894
00899 virtual XMLElement* createActiveXml()
00900 { return 0; }
00901
00911 virtual bool sendContent(Action action, const ObjList& contents, String* stanzaId = 0)
00912 { return false; }
00913
00923 inline bool sendContent(Action action, const JGSessionContent* content,
00924 String* stanzaId = 0) {
00925 if (!content)
00926 return false;
00927 ObjList tmp;
00928 tmp.append(content)->setDelete(false);
00929 return sendContent(action,tmp,stanzaId);
00930 }
00931
00940 virtual bool sendStreamHosts(const ObjList& hosts, String* stanzaId = 0)
00941 { return false; }
00942
00951 virtual bool sendStreamHostUsed(const char* jid, const char* stanzaId)
00952 { return false; }
00953
00958 void buildSocksDstAddr(String& buf);
00959
00967 bool sendInfo(XMLElement* xml, String* stanzaId = 0);
00968
00977 bool sendDtmf(const char* dtmf, unsigned int msDuration = 0, String* stanzaId = 0);
00978
00985 inline bool sendMessage(const char* msg) {
00986 return sendStanza(JBMessage::createMessage(JBMessage::Chat,
00987 m_localJID,m_remoteJID,0,msg),0,false);
00988 }
00989
00995 bool hasFeature(XMPPNamespace::Type feature);
00996
01004 static XMLElement* buildTransfer(const String& transferTo, const String& transferFrom,
01005 const String& sid = String::empty());
01006
01013 static inline Version lookupVersion(const char* value, Version def = VersionUnknown)
01014 { return (Version)lookup(value,s_versions,def); }
01015
01022 static inline const char* lookupVersion(int value, const char* def = "unknown")
01023 { return lookup(value,s_versions,def); }
01024
01031 static inline int lookupReason(const char* value, int def = ReasonOk)
01032 { return lookup(value,s_reasons,def); }
01033
01040 static inline const char* lookupReason(int value, const char* def = 0)
01041 { return lookup(value,s_reasons,def); }
01042
01048 static const char* lookupState(int state)
01049 { return lookup(state,s_states); }
01050
01057 static const char* lookupAction(int act, Version ver);
01058
01065 static Action lookupAction(const char* str, Version ver);
01066
01070 static TokenDict s_versions[];
01071
01075 static TokenDict s_reasons[];
01076
01080 static TokenDict s_states[];
01081
01085 static TokenDict s_actions0[];
01086
01090 static TokenDict s_actions1[];
01091
01092 protected:
01102 JGSession(Version ver, JGEngine* engine, JBStream* stream,
01103 const String& callerJID, const String& calledJID,
01104 const char* msg = 0);
01105
01113 JGSession(Version ver, JGEngine* engine, JBEvent* event, const String& id);
01114
01122 virtual bool initiate(const ObjList& contents, XMLElement* extra,
01123 const char* subject = 0) = 0;
01124
01131 virtual JGEvent* getEvent(u_int64_t time);
01132
01136 virtual void destroyed();
01137
01143 void enqueue(JBEvent* event);
01144
01153 bool sendStanza(XMLElement* stanza, String* stanzaId = 0, bool confirmation = true,
01154 bool ping = false);
01155
01161 bool sendPing(u_int64_t msecNow);
01162
01168 virtual JGEvent* decodeJingle(JBEvent* jbev) = 0;
01169
01178 virtual XMLElement* createJingle(Action action, XMLElement* element1 = 0,
01179 XMLElement* element2 = 0, XMLElement* element3 = 0) = 0;
01180
01187 virtual XMLElement* createDtmf(const char* dtmf, unsigned int msDuration = 0) = 0;
01188
01194 virtual void processJingleSetLastEvent(JBEvent& ev);
01195
01201 virtual bool processJabberIqResponse(JBEvent& ev);
01202
01207 virtual void processJabberIqEvent(JBEvent& ev);
01208
01213 void eventTerminated(JGEvent* event);
01214
01219 void changeState(State newState);
01220
01221 Version m_version;
01222
01223 State m_state;
01224 u_int64_t m_timeToPing;
01225
01226 JGEngine* m_engine;
01227 JBStream* m_stream;
01228
01229 bool m_outgoing;
01230 String m_sid;
01231 JabberID m_localJID;
01232 JabberID m_remoteJID;
01233
01234 ObjList m_events;
01235 JGEvent* m_lastEvent;
01236 bool m_recvTerminate;
01237 void* m_private;
01238
01239 String m_localSid;
01240 u_int32_t m_stanzaId;
01241 ObjList m_sentStanza;
01242
01243 private:
01244 JGSession() {}
01245 };
01246
01247
01252 class YJINGLE_API JGSession0 : public JGSession
01253 {
01254 friend class JGEvent;
01255 friend class JGEngine;
01256 public:
01260 virtual ~JGSession0();
01261
01267 virtual XMLElement* checkJingle(XMLElement* xml);
01268
01276 virtual bool accept(const ObjList& contents, String* stanzaId = 0);
01277
01278 protected:
01287 JGSession0(JGEngine* engine, JBStream* stream,
01288 const String& callerJID, const String& calledJID, const char* msg = 0);
01289
01296 JGSession0(JGEngine* engine, JBEvent* event, const String& id);
01297
01305 virtual bool initiate(const ObjList& contents, XMLElement* extra,
01306 const char* subject = 0);
01307
01317 virtual bool sendContent(Action action, const ObjList& contents, String* stanzaId = 0);
01318
01324 virtual JGEvent* decodeJingle(JBEvent* jbev);
01325
01334 virtual XMLElement* createJingle(Action action, XMLElement* element1 = 0,
01335 XMLElement* element2 = 0, XMLElement* element3 = 0);
01336
01343 virtual XMLElement* createDtmf(const char* dtmf, unsigned int msDuration = 0);
01344
01345 protected:
01346 String m_sessContentName;
01347 };
01348
01353 class YJINGLE_API JGSession1 : public JGSession
01354 {
01355 friend class JGEvent;
01356 friend class JGEngine;
01357 public:
01361 virtual ~JGSession1();
01362
01368 virtual XMLElement* checkJingle(XMLElement* xml);
01369
01377 virtual bool accept(const ObjList& contents, String* stanzaId = 0);
01378
01383 virtual XMLElement* createHoldXml();
01384
01389 virtual XMLElement* createActiveXml();
01390
01400 virtual bool sendContent(Action action, const ObjList& contents, String* stanzaId = 0);
01401
01410 virtual bool sendStreamHosts(const ObjList& hosts, String* stanzaId = 0);
01411
01420 virtual bool sendStreamHostUsed(const char* jid, const char* stanzaId);
01421
01422 protected:
01431 JGSession1(JGEngine* engine, JBStream* stream,
01432 const String& callerJID, const String& calledJID, const char* msg = 0);
01433
01440 JGSession1(JGEngine* engine, JBEvent* event, const String& id);
01441
01449 virtual bool initiate(const ObjList& contents, XMLElement* extra,
01450 const char* subject = 0);
01451
01457 virtual JGEvent* decodeJingle(JBEvent* jbev);
01458
01467 virtual XMLElement* createJingle(Action action, XMLElement* element1 = 0,
01468 XMLElement* element2 = 0, XMLElement* element3 = 0);
01469
01476 virtual XMLElement* createDtmf(const char* dtmf, unsigned int msDuration = 0);
01477
01481 virtual void processJabberIqEvent(JBEvent& ev);
01482
01483 };
01484
01489 class YJINGLE_API JGEvent
01490 {
01491 friend class JGSession;
01492 friend class JGSession0;
01493 friend class JGSession1;
01494 public:
01498 enum Type {
01499 Jingle,
01500 ResultOk,
01501 ResultError,
01502 ResultWriteFail,
01503 ResultTimeout,
01504
01505 Terminated,
01506
01507 Destroy,
01508 };
01509
01513 virtual ~JGEvent();
01514
01519 inline Type type() const
01520 { return m_type; }
01521
01526 inline const char* name()
01527 { return lookupType(m_type); }
01528
01533 inline JGSession* session() const
01534 { return m_session; }
01535
01540 inline XMLElement* element() const
01541 { return m_element; }
01542
01548 inline XMLElement* jingle() const
01549 { return m_jingle; }
01550
01555 inline JGSession::Action action() const
01556 { return m_action; }
01557
01562 inline const char* actionName() const
01563 { return m_session ? JGSession::lookupAction(m_action,m_session->version()) : ""; }
01564
01569 inline const String& id() const
01570 { return m_id; }
01571
01576 inline const String& reason() const
01577 { return m_reason; }
01578
01583 inline const String& text() const
01584 { return m_text; }
01585
01590 inline XMLElement* releaseXML() {
01591 TelEngine::destruct(m_jingle);
01592 XMLElement* tmp = m_element;
01593 m_element = 0;
01594 return tmp;
01595 }
01596
01601 inline bool final() const
01602 { return m_type == Terminated || m_type == Destroy; }
01603
01611 inline bool confirmElement(XMPPError::Type error = XMPPError::NoError,
01612 const char* text = 0, XMPPError::ErrorType type = XMPPError::TypeModify) {
01613 if (m_session && element() && !m_confirmed) {
01614 m_confirmed = true;
01615 if (error == XMPPError::NoError)
01616 return m_session->confirm(element());
01617 return m_session->confirm(releaseXML(),error,text,type);
01618 }
01619 return false;
01620 }
01621
01625 inline void setConfirmed()
01626 { m_confirmed = true; }
01627
01633 void setAction(JGSession::Action act);
01634
01639 static inline const char* lookupType(int type)
01640 { return lookup(type,s_typeName); }
01641
01645 static TokenDict s_typeName[];
01646
01650 ObjList m_contents;
01651
01655 ObjList m_streamHosts;
01656
01657 protected:
01666 inline JGEvent(Type type, JGSession* session, XMLElement* element = 0,
01667 const char* reason = 0, const char* text = 0)
01668 : m_type(type), m_confirmed(true), m_session(0), m_element(element),
01669 m_jingle(0), m_action(JGSession::ActCount), m_reason(reason), m_text(text)
01670 { init(session); }
01671
01680 inline JGEvent(JGSession::Action act, JGSession* session, XMLElement* element,
01681 const char* reason = 0, const char* text = 0)
01682 : m_type(Jingle), m_confirmed(false), m_session(0), m_element(element), m_jingle(0),
01683 m_action(act), m_reason(reason), m_text(text) {
01684 init(session);
01685 setAction(act);
01686 }
01687
01688 private:
01689 JGEvent() {}
01690 void init(JGSession* session);
01691
01692 Type m_type;
01693 bool m_confirmed;
01694 JGSession* m_session;
01695 XMLElement* m_element;
01696 XMLElement* m_jingle;
01697
01698 JGSession::Action m_action;
01699 String m_id;
01700 String m_reason;
01701 String m_text;
01702 };
01703
01709 class YJINGLE_API JGEngine : public JBService, public JBThreadList
01710 {
01711 friend class JGSession;
01712 public:
01719 JGEngine(JBEngine* engine, const NamedList* params, int prio = 0);
01720
01724 virtual ~JGEngine();
01725
01730 inline u_int64_t stanzaTimeout() const
01731 { return m_stanzaTimeout; }
01732
01737 inline u_int64_t pingInterval() const
01738 { return m_pingInterval; }
01739
01744 virtual void initialize(const NamedList& params);
01745
01752 JGEvent* getEvent(u_int64_t time);
01753
01766 JGSession* call(JGSession::Version ver, const String& callerName, const String& remoteJID,
01767 const ObjList& contents, XMLElement* extra = 0, const char* msg = 0,
01768 const char* subject = 0);
01769
01774 void defProcessEvent(JGEvent* event);
01775
01781 virtual void processEvent(JGEvent* event);
01782
01783 protected:
01791 virtual bool accept(JBEvent* event, bool& processed, bool& insert);
01792
01793 private:
01794
01795 void createSessionId(String& id);
01796
01797 ObjList m_sessions;
01798 Mutex m_sessionIdMutex;
01799 u_int32_t m_sessionId;
01800 u_int64_t m_stanzaTimeout;
01801 u_int64_t m_pingInterval;
01802 };
01803
01804
01809 class YJINGLE_API JGSentStanza : public String
01810 {
01811 public:
01819 JGSentStanza(const char* id, u_int64_t time, bool notif = false, bool ping = false)
01820 : String(id), m_time(time), m_notify(notif), m_ping(ping)
01821 {}
01822
01827 inline bool timeout(u_int64_t time) const
01828 { return time > m_time; }
01829
01834 inline bool notify() const
01835 { return m_notify; }
01836
01841 inline bool ping() const
01842 { return m_ping; }
01843
01844 private:
01845 u_int64_t m_time;
01846 bool m_notify;
01847 bool m_ping;
01848 };
01849
01850 };
01851
01852 #endif
01853
01854