Yate
|
00001 00024 #ifndef __YATEJABBER_H 00025 #define __YATEJABBER_H 00026 00027 #include <xmpputils.h> 00028 00032 namespace TelEngine { 00033 00034 class SASL; // SASL authentication mechanism 00035 class JBEvent; // A Jabber event 00036 class JBStream; // A Jabber stream 00037 class JBClientStream; // A client to server stream 00038 class JBServerStream; // A server to server stream 00039 class JBClusterStream; // A cluster stream 00040 class JBRemoteDomainDef; // Options and connect settings for a remote domain 00041 class JBConnect; // A socket connector 00042 class JBEngine; // A Jabber engine 00043 class JBServerEngine; // A Jabber server engine 00044 class JBClientEngine; // A Jabber client engine 00045 class JBStreamSet; // A set of streams to be processed in an uniform way 00046 class JBStreamSetProcessor; // Specialized stream processor 00047 class JBStreamSetReceive; // Specialized stream data receiver 00048 class JBStreamSetList; // A list of stream sets 00049 class JBEntityCaps; // Entity capability 00050 class JBEntityCapsList; // Entity capability list manager 00051 00052 00056 #define XMPP_C2S_PORT 5222 00057 00061 #define XMPP_S2S_PORT 5269 00062 00067 #define XMPP_MAX_INCOMPLETEXML 8192 00068 00069 00074 class YJABBER_API SASL : public GenObject 00075 { 00076 YCLASS(SASL,GenObject) 00077 public: 00083 SASL(bool plain, const char* realm = 0); 00084 00088 ~SASL() 00089 { TelEngine::destruct(m_params); } 00090 00096 void setAuthParams(const char* user = 0, const char* pwd = 0); 00097 00104 bool buildAuthRsp(String& buf, const char* digestUri = 0); 00105 00111 inline void buildAuthRspReply(String& buf, const String& rsp) { 00112 if (m_plain) 00113 return; 00114 String tmp("rspauth=" + rsp); 00115 Base64 b((void*)tmp.c_str(),tmp.length(),false); 00116 b.encode(buf); 00117 b.clear(false); 00118 } 00119 00125 inline bool validAuthReply(const String& reply) { 00126 String tmp; 00127 if (m_params) 00128 buildMD5Digest(tmp,m_params->getValue("password"),false); 00129 return tmp == reply; 00130 } 00131 00138 bool buildMD5Challenge(String& buf); 00139 00147 inline void buildMD5Digest(String& dest, const char* password, 00148 bool challengeRsp = true) { 00149 if (m_params) 00150 buildMD5Digest(dest,*m_params,password,challengeRsp); 00151 } 00152 00158 bool parsePlain(const DataBlock& buf); 00159 00165 bool parseMD5Challenge(const String& buf); 00166 00173 bool parseMD5ChallengeRsp(const String& buf); 00174 00184 static bool parsePlain(const DataBlock& buf, String& user, String& pwd, 00185 String* authzid = 0); 00186 00195 static void buildMD5Digest(String& dest, const NamedList& params, 00196 const char* password, bool challengeRsp = true); 00197 00198 bool m_plain; 00199 NamedList* m_params; 00200 String m_realm; 00201 String m_nonce; 00202 String m_cnonce; 00203 unsigned int m_nonceCount; 00204 00205 private: 00206 SASL() {} 00207 }; 00208 00209 00215 class YJABBER_API JBEvent : public RefObject 00216 { 00217 YCLASS(JBEvent,RefObject) 00218 friend class JBStream; 00219 friend class JBClientStream; 00220 friend class JBServerStream; 00221 public: 00225 enum Type { 00226 // Stream terminated. Try to connect or wait to be destroyed 00227 Terminated, 00228 // Stream is destroying 00229 Destroy, 00230 // Stream start was received: when processing this event, the upper 00231 // layer must call stream's start() method or terminate the stream 00232 Start, 00233 // Incoming stream need auth: when processing this event, the upper 00234 // layer must call stream's authenticated() method 00235 // Component: the event's text contains the handshake data 00236 Auth, 00237 // The event's element is an 'iq' with a child qualified by bind namespace 00238 // This event is generated by an incoming client stream without a bound resource 00239 Bind, 00240 // Stream is running (can send/recv stanzas) 00241 Running, 00242 // The event's element is a 'message' 00243 Message, 00244 // The event's element is a 'presence' 00245 Presence, 00246 // The event's element is an 'iq' 00247 Iq, 00248 // The event's element is a 'db:result' one received by a server-to-server stream 00249 // containing the dialback key to verify 00250 // The event's text is filled with dialback key to verify 00251 DbResult, 00252 // The event's element is a 'db:verify' one received by a server-to-server stream 00253 DbVerify, 00254 // New user register or user password change succeeded 00255 RegisterOk, 00256 // New user register or user password change failed 00257 // The event's element is the response 00258 RegisterFailed, 00259 // Non stanza element received in Running state 00260 Unknown 00261 }; 00262 00272 inline JBEvent(Type type, JBStream* stream, XmlElement* element, 00273 const JabberID& from, const JabberID& to, XmlElement* child = 0) 00274 : m_type(type), m_stream(0), m_link(true), m_element(element), 00275 m_child(child) 00276 { init(stream,element,&from,&to); } 00277 00285 inline JBEvent(Type type, JBStream* stream, XmlElement* element, 00286 XmlElement* child = 0) 00287 : m_type(type), m_stream(0), m_link(true), m_element(element), 00288 m_child(child) 00289 { init(stream,element); } 00290 00294 virtual ~JBEvent(); 00295 00300 inline int type() const 00301 { return m_type; } 00302 00307 inline const char* name() const 00308 { return lookup(type()); } 00309 00314 inline const String& stanzaType() const 00315 { return m_stanzaType; } 00316 00321 inline const JabberID& from() const 00322 { return m_from; } 00323 00328 inline const JabberID& to() const 00329 { return m_to; } 00330 00336 inline const String& id() const 00337 { return m_id; } 00338 00343 inline const String& text() const 00344 { return m_text; } 00345 00350 inline JBStream* stream() const 00351 { return m_stream; } 00352 00357 JBClientStream* clientStream(); 00358 00363 JBServerStream* serverStream(); 00364 00369 JBClusterStream* clusterStream(); 00370 00375 inline XmlElement* element() const 00376 { return m_element; } 00377 00382 inline XmlElement* child() const 00383 { return m_child; } 00384 00391 XmlElement* releaseXml(bool del = false); 00392 00399 XmlElement* buildIqResult(bool addTags, XmlElement* child = 0); 00400 00407 bool sendIqResult(XmlElement* child = 0); 00408 00419 XmlElement* buildIqError(bool addTags, XMPPError::Type error, const char* reason = 0, 00420 XMPPError::ErrorType type = XMPPError::TypeModify); 00421 00430 bool sendStanzaError(XMPPError::Type error, const char* reason = 0, 00431 XMPPError::ErrorType type = XMPPError::TypeModify); 00432 00437 void releaseStream(bool release = false); 00438 00443 inline static const char* lookup(int type) 00444 { return TelEngine::lookup(type,s_type); } 00445 00446 private: 00447 static const TokenDict s_type[]; // Event names 00448 JBEvent() {} // Don't use it! 00449 bool init(JBStream* stream, XmlElement* element, 00450 const JabberID* from = 0, const JabberID* to = 0); 00451 00452 Type m_type; // Type of this event 00453 JBStream* m_stream; // The stream that generated this event 00454 bool m_link; // Stream link state 00455 XmlElement* m_element; // Received XML element, if any 00456 XmlElement* m_child; // The first child element for 'iq' elements 00457 String m_stanzaType; // Stanza's 'type' attribute 00458 JabberID m_from; // Stanza's 'from' attribute 00459 JabberID m_to; // Stanza's 'to' attribute 00460 String m_id; // 'id' attribute if the received element has one 00461 String m_text; // The stanza's text or termination reason for 00462 // Terminated/Destroy events 00463 }; 00464 00465 00471 class YJABBER_API JBStream : public RefObject, public DebugEnabler, public Mutex 00472 { 00473 friend class JBEngine; 00474 friend class JBEvent; 00475 public: 00479 enum Type { 00480 c2s = 0, // Client to server 00481 s2s, // Server to server 00482 comp, // External component 00483 cluster, // Cluster stream 00484 TypeCount // Unknown 00485 }; 00486 00490 enum State { 00491 Idle = 0, // Stream is waiting to be connected or destroyed 00492 Connecting, // Outgoing stream is waiting for the socket to connect 00493 WaitStart, // Waiting for remote's stream start 00494 // (outgoing: stream start already sent) 00495 Starting, // Incoming stream is processing a stream start element 00496 Features, // Outgoing: waiting for stream features 00497 // Incoming: stream features sent 00498 WaitTlsRsp, // 'starttls' sent: waiting for response 00499 Securing, // Stream is currently negotiating the TLS 00500 Auth, // Auth element (db:result for s2s streams) sent 00501 // Incoming comp: handshake received 00502 Challenge, // 'challenge' element sent/received 00503 Compressing, // Stream is negotiating compression 00504 // outgoing: compress element sent, wait for response 00505 // incoming: waiting for <compressed> element to be sent 00506 Register, // A new user is currently registering 00507 // Keep Running state here: we expect all other states 00508 // (except for Destroy) to have lower values 00509 Running, // Established. Allow XML stanzas to pass over the stream 00510 Destroy, // Stream is destroying. No more traffic allowed 00511 }; 00512 00516 enum Flags { 00517 NoAutoRestart = 0x00000001,// Don't restart stream when down 00518 TlsRequired = 0x00000002,// TLS is mandatory on this stream 00519 AllowPlainAuth = 0x00000004,// Allow plain password authentication 00520 // If not allowed and this is the only method 00521 // offered by server the stream will be terminated 00522 DialbackOnly = 0x00000008,// Outgoing s2s dialback stream 00523 RegisterUser = 0x00000010,// Outgoing c2s register new user 00524 Compress = 0x00000020,// Offer/handle compression 00525 InError = 0x00000080,// The stream was terminated with error 00526 // Flags to be managed by the upper layer 00527 RosterRequested = 0x00000100,// c2s: the roster was already requested 00528 AvailableResource = 0x00000200,// c2s: available presence was sent/received 00529 PositivePriority = 0x00000400,// c2s: the resource advertised by the client has priority >= 0 00530 // Internal flags (cleared when the stream is re-started) 00531 SetCompressed = 0x00010000,// Set StreamCompressed flag after succesfully sending 00532 // the current stream xml buffer 00533 StreamSecured = 0x00020000,// TLS stage was done (possible without using TLS) 00534 StreamTls = 0x00040000,// The stream is using TLS 00535 StreamAuthenticated = 0x00080000,// Stream already authenticated 00536 StreamRemoteVer1 = 0x00100000,// Remote party advertised RFC3920 version=1.0 00537 StreamLocalVer1 = 0x00200000,// Advertise RFC3920 version=1.0 on incoming streams 00538 StreamWaitBindRsp = 0x01000000,// Outgoing c2s waiting for bind response 00539 StreamWaitSessRsp = 0x02000000,// Outgoing c2s waiting for session response 00540 StreamWaitChallenge = 0x04000000,// Outgoing waiting for auth challenge 00541 StreamWaitChgRsp = 0x08000000,// Outgoing waiting challenge response confirmation 00542 StreamRfc3920Chg = 0x10000000,// Outgoing sent empty response to challenge with rspauth (RFC3920) 00543 StreamCompressed = 0x20000000,// The stream is using compression 00544 StreamCanCompress = 0x40000000,// Incoming s2s may still be compressed 00545 // Flag masks 00546 StreamFlags = 0x000000ff, 00547 InternalFlags = 0xffff0000, 00548 }; 00549 00554 virtual ~JBStream(); 00555 00560 inline int type() const 00561 { return m_type; } 00562 00567 inline int xmlns() const 00568 { return m_xmlns; } 00569 00574 inline State state() const 00575 { return m_state; } 00576 00581 inline bool incoming() const 00582 { return m_incoming; } 00583 00588 inline bool outgoing() const 00589 { return !m_incoming; } 00590 00595 inline JBEngine* engine() const 00596 { return m_engine; } 00597 00602 inline const char* name() const 00603 { return m_name; } 00604 00609 inline const String& id() const 00610 { return m_id; } 00611 00618 inline bool isId(const String& str) { 00619 Lock lock(this); 00620 return str == m_id; 00621 } 00622 00627 inline const JabberID& local() const 00628 { return m_local; } 00629 00635 inline void local(JabberID& jid) { 00636 Lock lock(this); 00637 jid = m_local; 00638 } 00639 00644 inline void setLocal(const char* jid) 00645 { m_local.set(jid); } 00646 00651 inline const JabberID& remote() const 00652 { return m_remote; } 00653 00659 inline void remote(JabberID& jid) { 00660 Lock lock(this); 00661 jid = m_remote; 00662 } 00663 00670 inline bool remoteAddr(SocketAddr& addr) { 00671 Lock lock(this); 00672 return m_socket && m_socket->getPeerName(addr); 00673 } 00674 00681 inline bool localAddr(SocketAddr& addr) { 00682 Lock lock(this); 00683 return m_socket && m_socket->getSockName(addr); 00684 } 00685 00690 inline int flags() const 00691 { return m_flags; } 00692 00698 inline bool flag(int mask) const 00699 { return 0 != (m_flags & mask); } 00700 00706 inline void setTlsRequired(bool set) { 00707 Lock lock(this); 00708 if (set) 00709 setFlags(TlsRequired); 00710 else 00711 resetFlags(TlsRequired); 00712 } 00713 00720 bool haveData(); 00721 00731 void connectAddr(String& addr, int& port, String& localip, int& stat, 00732 ObjList& srvs) const; 00733 00739 inline const String& serverHost() const 00740 { return m_serverHost ? m_serverHost : m_remote.domain(); } 00741 00747 void setRosterRequested(bool ok); 00748 00756 bool setAvailableResource(bool ok, bool positive = true); 00757 00765 bool readSocket(char* buf, unsigned int len); 00766 00771 virtual JBClientStream* clientStream() 00772 { return 0; } 00773 00778 virtual JBServerStream* serverStream() 00779 { return 0; } 00780 00785 virtual JBClusterStream* clusterStream() 00786 { return 0; } 00787 00794 JBEvent* getEvent(u_int64_t time = Time::msecNow()); 00795 00802 bool sendStanza(XmlElement*& xml); 00803 00815 bool sendStreamXml(State newState, XmlElement* first, XmlElement* second = 0, 00816 XmlElement* third = 0); 00817 00829 void start(XMPPFeatureList* features = 0, XmlElement* caps = 0, bool useVer1 = true); 00830 00844 bool authenticated(bool ok, const String& rsp = String::empty(), 00845 XMPPError::Type error = XMPPError::NotAuthorized, 00846 const char* username = 0, const char* id = 0, const char* resource = 0); 00847 00860 void terminate(int location, bool destroy, XmlElement* xml, 00861 int error = XMPPError::NoError, const char* reason = "", 00862 bool final = false); 00863 00869 virtual void connectTerminated(Socket*& sock); 00870 00879 virtual bool connecting(bool sync, int stat, ObjList& srvs); 00880 00885 virtual void* getObject(const String& name) const; 00886 00891 inline const char* stateName() const 00892 { return lookup(state(),s_stateName); } 00893 00898 inline const char* typeName() const 00899 { return lookup(type(),s_typeName); } 00900 00906 inline void buildSha1Digest(String& buf, const String& secret) { 00907 SHA1 sha(id() + secret); 00908 buf = sha.hexDigest(); 00909 buf.toLower(); 00910 } 00911 00916 virtual const String& toString() const; 00917 00924 static inline Type lookupType(const char* text, Type defVal = TypeCount) 00925 { return (Type)lookup(text,s_typeName,defVal); } 00926 00930 SASL* m_sasl; 00931 00935 static const TokenDict s_stateName[]; 00936 00940 static const TokenDict s_flagName[]; 00941 00945 static const TokenDict s_typeName[]; 00946 00947 protected: 00955 JBStream(JBEngine* engine, Socket* socket, Type t, bool ssl = false); 00956 00967 JBStream(JBEngine* engine, Type t, const JabberID& local, const JabberID& remote, 00968 const char* name = 0, const NamedList* params = 0, const char* serverHost = 0); 00969 00973 virtual void destroyed(); 00974 00982 virtual bool canProcess(u_int64_t time); 00983 00989 virtual void process(u_int64_t time); 00990 00998 virtual bool processRunning(XmlElement* xml, const JabberID& from, 00999 const JabberID& to); 01000 01007 virtual void checkTimeouts(u_int64_t time); 01008 01014 virtual void resetConnection(Socket* sock = 0); 01015 01020 virtual XmlElement* buildStreamStart(); 01021 01029 virtual bool processStart(const XmlElement* xml, const JabberID& from, 01030 const JabberID& to); 01031 01039 virtual bool processAuth(XmlElement* xml, const JabberID& from, 01040 const JabberID& to); 01041 01049 virtual bool processCompressing(XmlElement* xml, const JabberID& from, 01050 const JabberID& to); 01051 01059 virtual bool processRegister(XmlElement* xml, const JabberID& from, 01060 const JabberID& to); 01061 01071 bool processStreamStart(const XmlElement* xml); 01072 01079 bool handleCompressReq(XmlElement* xml); 01080 01086 bool streamError(XmlElement* xml); 01087 01095 bool getJids(XmlElement* xml, JabberID& from, JabberID& to); 01096 01108 bool checkStanzaRecv(XmlElement* xml, JabberID& from, JabberID& to); 01109 01115 void changeState(State newState, u_int64_t time = Time::msecNow()); 01116 01121 XmlElement* checkCompress(); 01122 01126 void checkPendingEvent(); 01127 01134 bool sendPending(bool streamOnly = false); 01135 01142 bool writeSocket(const void* data, unsigned int& len); 01143 01147 void updateFromRemoteDef(); 01148 01153 XMPPFeature* firstRequiredFeature(); 01154 01161 bool dropXml(XmlElement*& xml, const char* reason); 01162 01170 inline bool destroyDropXml(XmlElement*& xml, XMPPError::Type error, const char* reason) { 01171 dropXml(xml,reason); 01172 terminate(0,true,0,error); 01173 return false; 01174 } 01175 01180 void setFlags(int mask); 01181 01186 void resetFlags(int mask); 01187 01191 inline void setSecured() { 01192 setFlags(StreamSecured); 01193 m_features.remove(XMPPNamespace::Tls); 01194 } 01195 01200 void setIdleTimer(u_int64_t msecNow = Time::msecNow()); 01201 01202 State m_state; // Stream state 01203 String m_id; // Stream id 01204 JabberID m_local; // Local peer's jid 01205 JabberID m_remote; // Remote peer's jid 01206 String m_serverHost; // Outgoing: optional server host (replaces remote domain when connecting) 01207 int m_flags; // Stream flags 01208 XMPPNamespace::Type m_xmlns; // Stream namespace 01209 XMPPFeatureList m_features; // Advertised features 01210 JBEvent* m_lastEvent; // Last event generated by this stream 01211 ObjList m_events; // Queued events 01212 ObjList m_pending; // Pending outgoing elements 01213 // Timers 01214 u_int64_t m_setupTimeout; // Overall stream setup timeout 01215 u_int64_t m_startTimeout; // Incoming: wait stream start period 01216 u_int64_t m_pingTimeout; // Sent ping timeout 01217 u_int64_t m_nextPing; // Next ping 01218 u_int64_t m_idleTimeout; // Stream idle timeout 01219 u_int64_t m_connectTimeout; // Stream connect timeout 01220 // 01221 unsigned int m_restart; // Remaining restarts 01222 u_int64_t m_timeToFillRestart; // The next time to increase the restart counter 01223 01224 String m_pingId; 01225 01226 private: 01227 // Forbidden default constructor 01228 inline JBStream() {} 01229 // Process incoming elements in Challenge state 01230 // The element will be consumed 01231 // Return false if stream termination was initiated 01232 bool processChallenge(XmlElement* xml, const JabberID& from, 01233 const JabberID& to); 01234 // Process incoming 'auth' elements qualified by SASL namespace 01235 // The element will be consumed 01236 // Return false if stream termination was initiated 01237 bool processSaslAuth(XmlElement* xml, const JabberID& from, 01238 const JabberID& to); 01239 // Process received elements in Features state (incoming stream) 01240 // The element will be consumed 01241 // Return false if stream termination was initiated 01242 bool processFeaturesIn(XmlElement* xml, const JabberID& from, 01243 const JabberID& to); 01244 // Process received elements in Features state (outgoing stream) 01245 // The element will be consumed 01246 // Return false if stream termination was initiated 01247 bool processFeaturesOut(XmlElement* xml, const JabberID& from, 01248 const JabberID& to); 01249 // Process received elements in WaitTlsRsp state (outgoing stream) 01250 // The element will be consumed 01251 // Return false if stream termination was initiated 01252 bool processWaitTlsRsp(XmlElement* xml, const JabberID& from, 01253 const JabberID& to); 01254 // Set stream namespace from type 01255 void setXmlns(); 01256 // Event termination notification 01257 // @param event The notifier. Ignored if it's not m_lastEvent 01258 void eventTerminated(const JBEvent* event); 01259 // Compress data to be sent (the pending stream xml buffer or pending stanza) 01260 // Return false on failure 01261 bool compress(XmlElementOut* xml = 0); 01262 // Reset connect status data 01263 void resetConnectStatus(); 01264 // Postpone stream terminate until all parsed elements are processed 01265 // Terminate now if allowed 01266 // This method is thread safe 01267 void postponeTerminate(int location, bool destroy, int error, const char* reason); 01268 // Handle postponed termination. Return true if found 01269 // This method is not thread safe 01270 bool postponedTerminate(); 01271 // Reset postponed terminate data 01272 inline void resetPostponedTerminate() { 01273 m_ppTerminateTimeout = 0; 01274 TelEngine::destruct(m_ppTerminate); 01275 } 01276 01277 enum { 01278 SocketCanRead = 0x01, 01279 SocketReading = 0x02, 01280 SocketCanWrite = 0x10, 01281 SocketWriting = 0x20, 01282 SocketWaitReset = 0x80, 01283 }; 01284 inline void socketSetCanRead(bool ok) { 01285 Lock lock(m_socketMutex); 01286 if (ok) 01287 m_socketFlags |= SocketCanRead; 01288 else 01289 m_socketFlags &= ~SocketCanRead; 01290 } 01291 inline void socketSetReading(bool ok) { 01292 if (ok) 01293 m_socketFlags |= SocketReading; 01294 else 01295 m_socketFlags &= ~SocketReading; 01296 } 01297 inline void socketSetCanWrite(bool ok) { 01298 Lock lock(m_socketMutex); 01299 if (ok) 01300 m_socketFlags |= SocketCanWrite; 01301 else 01302 m_socketFlags &= ~SocketCanWrite; 01303 } 01304 inline void socketSetWriting(bool ok) { 01305 if (ok) 01306 m_socketFlags |= SocketWriting; 01307 else 01308 m_socketFlags &= ~SocketWriting; 01309 } 01310 inline bool socketCanRead() const { 01311 return m_socket && (m_socketFlags & SocketCanRead) && 01312 !socketWaitReset(); 01313 } 01314 inline bool socketCanWrite() const { 01315 return m_socket && (m_socketFlags & SocketCanWrite) && 01316 !socketWaitReset(); 01317 } 01318 inline bool socketReading() const 01319 { return (m_socketFlags & SocketReading) != 0; } 01320 inline bool socketWriting() const 01321 { return (m_socketFlags & SocketWriting) != 0; } 01322 inline bool socketWaitReset() const 01323 { return 0 != (m_socketFlags & SocketWaitReset); } 01324 01325 JBEngine* m_engine; // The owner of this stream 01326 int m_type; // Stream type 01327 bool m_incoming; // Stream direction 01328 String m_name; // Local (internal) name 01329 JBEvent* m_terminateEvent; // Pending terminate event 01330 NamedList* m_ppTerminate; // Postponed terminate parameters 01331 u_int64_t m_ppTerminateTimeout; // Postponed terminate timeout 01332 // Pending outgoing XML 01333 String m_outStreamXml; 01334 DataBlock m_outStreamXmlCompress; 01335 DataBlock m_outXmlCompress; 01336 // Connection related data 01337 XmlDomParser* m_xmlDom; 01338 Socket* m_socket; 01339 char m_socketFlags; // Socket flags: 0: unavailable 01340 Mutex m_socketMutex; // Protect the socket and parser 01341 String m_connectAddr; // Remote ip to connect to 01342 int m_connectPort; // Remote port to connect to 01343 String m_localIp; // Local ip to bind when connecting 01344 Compressor* m_compress; 01345 int m_connectStatus; // Current connect stream status 01346 ObjList m_connectSrvs; // Current connect stream SRV records 01347 }; 01348 01349 01354 class YJABBER_API JBClientStream : public JBStream 01355 { 01356 YCLASS(JBClientStream,JBStream) 01357 friend class JBStream; 01358 public: 01365 JBClientStream(JBEngine* engine, Socket* socket, bool ssl = false); 01366 01376 JBClientStream(JBEngine* engine, const JabberID& jid, const String& account, 01377 const NamedList& params, const char* name = 0, const char* serverHost = 0); 01378 01383 inline const String& account() const 01384 { return m_account; } 01385 01390 inline GenObject* userData() 01391 { return m_userData; } 01392 01398 inline void userData(GenObject* data) { 01399 Lock lock(this); 01400 TelEngine::destruct(m_userData); 01401 m_userData = data; 01402 } 01403 01408 virtual JBClientStream* clientStream() 01409 { return this; } 01410 01419 void bind(const String& resource, const char* id, 01420 XMPPError::Type error = XMPPError::NoError); 01421 01431 bool requestRegister(bool data, bool set = true, 01432 const String& newPass = String::empty()); 01433 01434 protected: 01442 virtual bool processRunning(XmlElement* xml, const JabberID& from, 01443 const JabberID& to); 01444 01452 virtual bool processStart(const XmlElement* xml, const JabberID& from, 01453 const JabberID& to); 01454 01462 virtual bool processAuth(XmlElement* xml, const JabberID& from, 01463 const JabberID& to); 01464 01472 virtual bool processRegister(XmlElement* xml, const JabberID& from, 01473 const JabberID& to); 01474 01478 virtual void destroyed(); 01479 01484 bool startAuth(); 01485 01490 bool bind(); 01491 01492 private: 01493 inline bool isRegisterId(XmlElement& xml) { 01494 if (!m_registerReq) 01495 return false; 01496 String* id = xml.getAttribute("id"); 01497 return id && id->length() == 1 && (*id)[0] == m_registerReq; 01498 } 01499 01500 String m_account; // Stream account 01501 GenObject* m_userData; // User (upper layer) data 01502 String m_password; // The password 01503 String m_newPassword; // New password 01504 char m_registerReq; // Register requested. 1(data) 2(register) 3(remove) 01505 }; 01506 01507 01512 class YJABBER_API JBServerStream : public JBStream 01513 { 01514 YCLASS(JBServerStream,JBStream) 01515 friend class JBStream; 01516 public: 01523 JBServerStream(JBEngine* engine, Socket* socket, bool component = false); 01524 01535 JBServerStream(JBEngine* engine, const JabberID& local, const JabberID& remote, 01536 const char* dbId = 0, const char* dbKey = 0, bool dbOnly = false, 01537 const NamedList* params = 0); 01538 01547 JBServerStream(JBEngine* engine, const JabberID& local, const JabberID& remote, 01548 const String* name = 0, const NamedList* params = 0); 01549 01554 inline bool dialback() const 01555 { return outgoing() && flag(DialbackOnly); } 01556 01562 inline const NamedList& remoteDomains() const 01563 { return m_remoteDomains; } 01564 01572 inline bool hasRemoteDomain(const String& domain, bool auth = true) { 01573 NamedString* tmp = m_remoteDomains.getParam(domain); 01574 return tmp && (!auth || tmp->null()); 01575 } 01576 01581 inline NamedString* takeDb() { 01582 Lock lock(this); 01583 NamedString* tmp = m_dbKey; 01584 m_dbKey = 0; 01585 return tmp; 01586 } 01587 01592 virtual JBServerStream* serverStream() 01593 { return this; } 01594 01604 bool sendDbVerify(const char* from, const char* to, const char* id, 01605 XMPPError::Type rsp = XMPPError::NoError); 01606 01616 bool sendDbResult(const JabberID& from, const JabberID& to, 01617 XMPPError::Type rsp = XMPPError::NoError); 01618 01623 bool sendDialback(); 01624 01632 bool startComp(const String& local = String::empty(), const String& remote = String::empty()); 01633 01634 protected: 01638 virtual void destroyed(); 01639 01647 virtual bool processRunning(XmlElement* xml, const JabberID& from, 01648 const JabberID& to); 01649 01654 virtual XmlElement* buildStreamStart(); 01655 01663 virtual bool processStart(const XmlElement* xml, const JabberID& from, 01664 const JabberID& to); 01665 01673 virtual bool processAuth(XmlElement* xml, const JabberID& from, 01674 const JabberID& to); 01675 01683 bool processDbResult(XmlElement* xml, const JabberID& from, const JabberID& to); 01684 01690 inline void adjustDbRsp(XMPPError::Type& rsp) { 01691 Lock lock(this); 01692 if (!flag(StreamRemoteVer1) && rsp != XMPPError::NoError) 01693 rsp = XMPPError::NotAuthorized; 01694 } 01695 01700 NamedList m_remoteDomains; 01701 01702 private: 01703 NamedString* m_dbKey; // Outgoing: initial dialback key to check 01704 String m_password; // Outgoing component: password 01705 }; 01706 01707 01712 class YJABBER_API JBClusterStream : public JBStream 01713 { 01714 YCLASS(JBClusterStream,JBStream) 01715 friend class JBStream; 01716 public: 01722 JBClusterStream(JBEngine* engine, Socket* socket); 01723 01731 JBClusterStream(JBEngine* engine, const JabberID& local, const JabberID& remote, 01732 const NamedList* params = 0); 01733 01738 virtual JBClusterStream* clusterStream() 01739 { return this; } 01740 01741 protected: 01746 virtual XmlElement* buildStreamStart(); 01747 01755 virtual bool processStart(const XmlElement* xml, const JabberID& from, 01756 const JabberID& to); 01757 01765 virtual bool processRunning(XmlElement* xml, const JabberID& from, 01766 const JabberID& to); 01767 }; 01768 01769 01775 class YJABBER_API JBRemoteDomainDef : public String 01776 { 01777 YCLASS(JBRemoteDomainDef,String) 01778 public: 01783 inline JBRemoteDomainDef(const char* domain = 0) 01784 : String(domain), m_port(0), m_flags(0) 01785 {} 01786 01790 String m_address; 01791 01795 int m_port; 01796 01800 int m_flags; 01801 }; 01802 01803 01809 class YJABBER_API JBConnect : public GenObject 01810 { 01811 YCLASS(JBConnect,GenObject) 01812 public: 01813 enum Status { 01814 Start = 0, 01815 Address, // Use configured address 01816 Srv, // Use SRV records 01817 Domain // Use stream remote domain 01818 }; 01819 01824 JBConnect(const JBStream& stream); 01825 01829 virtual ~JBConnect(); 01830 01834 virtual void stopConnect(); 01835 01840 virtual const String& toString() const; 01841 01845 static const TokenDict s_statusName[]; 01846 01847 protected: 01855 void connect(); 01856 01857 private: 01858 // No default constructor 01859 inline JBConnect() 01860 {} 01861 // Check if exiting. Release socket if exiting 01862 bool exiting(Socket*& sock); 01863 // Create and try to connect a socket. Return it on success 01864 // Set stop on fatal failure and return 0 01865 Socket* connect(const char* addr, int port, bool& stop); 01866 // Notify termination, remove from engine 01867 void terminated(Socket* sock, bool final); 01868 // Notify connecting to the stream. Return false if stream vanished 01869 bool notifyConnecting(bool sync, bool useCurrentStat = false); 01870 // Delete a socket and zero the pointer 01871 void deleteSocket(Socket*& sock); 01872 // Advance connect status 01873 void advanceStatus(); 01874 01875 int m_status; // Current status 01876 String m_domain; // Remote domain 01877 String m_address; // Remote ip address 01878 int m_port; // Port to connect to 01879 JBEngine* m_engine; // The engine owning this connector 01880 String m_stream; // Stream name 01881 JBStream::Type m_streamType; // Stream type 01882 String m_localIp; // Local ip to bind when connecting 01883 ObjList m_srvs; // SRV records list 01884 }; 01885 01886 01891 class YJABBER_API JBEngine : public DebugEnabler, public Mutex, public GenObject 01892 { 01893 YCLASS(JBEngine,GenObject) 01894 friend class JBStream; 01895 friend class JBConnect; 01896 friend class JBStreamSetProcessor; 01897 public: 01902 JBEngine(const char* name = "jbengine"); 01903 01907 virtual ~JBEngine(); 01908 01913 inline unsigned int streamReadBuffer() const 01914 { return m_streamReadBuffer; } 01915 01920 inline bool exiting() const 01921 { return m_exiting; } 01922 01926 inline void setExiting() { 01927 if (m_exiting) 01928 return; 01929 m_exiting = true; 01930 dropAll(JBStream::TypeCount,JabberID::empty(),JabberID::empty(), 01931 XMPPError::Shutdown); 01932 } 01933 01938 inline bool hasClientTls() const 01939 { return m_hasClientTls; } 01940 01947 inline JBRemoteDomainDef* remoteDomainDef(const String& domain) { 01948 ObjList* o = m_remoteDomains.find(domain); 01949 return o ? static_cast<JBRemoteDomainDef*>(o->get()) : &m_remoteDomain; 01950 } 01951 01955 virtual void destruct(); 01956 01961 virtual void initialize(const NamedList& params); 01962 01968 virtual void cleanup(bool final = false, bool waitTerminate = true); 01969 01979 bool acceptConn(Socket* sock, SocketAddr& remote, JBStream::Type t, bool ssl = false); 01980 01987 virtual JBStream* findStream(const String& id, 01988 JBStream::Type hint = JBStream::TypeCount); 01989 01999 ObjList* findClientStreams(bool in, const JabberID& jid, int flags = 0xffffffff); 02000 02012 ObjList* findClientStreams(bool in, const JabberID& jid, const ObjList& resources, 02013 int flags = 0xffffffff); 02014 02022 JBClientStream* findClientStream(bool in, const JabberID& jid); 02023 02033 virtual unsigned int dropAll(JBStream::Type type = JBStream::TypeCount, 02034 const JabberID& local = JabberID::empty(), 02035 const JabberID& remote = JabberID::empty(), 02036 XMPPError::Type error = XMPPError::NoError, const char* reason = 0); 02037 02043 virtual void buildStreamName(String& name, const JBStream* stream) 02044 {} 02045 02051 virtual bool hasDomain(const String& domain) 02052 { return false; } 02053 02059 virtual void processEvent(JBEvent* ev); 02060 02068 virtual void returnEvent(JBEvent* ev, XMPPError::Type error = XMPPError::NoError, 02069 const char* reason = 0); 02070 02075 virtual void encryptStream(JBStream* stream); 02076 02081 virtual void connectStream(JBStream* stream); 02082 02088 virtual void compressStream(JBStream* stream, const String& formats); 02089 02097 virtual void buildDialbackKey(const String& id, const String& local, 02098 const String& remote, String& key); 02099 02105 bool checkDupId(JBStream* stream); 02106 02113 virtual void printXml(const JBStream* stream, bool send, XmlChild& xml) const; 02114 02121 virtual void printXml(const JBStream* stream, bool send, XmlFragment& frag) const; 02122 02123 protected: 02128 virtual void addStream(JBStream* stream); 02129 02136 virtual void removeStream(JBStream* stream, bool delObj = true); 02137 02142 virtual void stopStreamSets(bool waitTerminate = true) 02143 {} 02144 02151 virtual void getStreamList(RefPointer<JBStreamSetList>& list, int type) 02152 {} 02153 02160 inline void getStreamLists(RefPointer<JBStreamSetList> list[JBStream::TypeCount], 02161 int type = JBStream::TypeCount) { 02162 if (type == JBStream::c2s || type == JBStream::TypeCount) 02163 getStreamList(list[JBStream::c2s],JBStream::c2s); 02164 if (type == JBStream::s2s || type == JBStream::TypeCount) 02165 getStreamList(list[JBStream::s2s],JBStream::s2s); 02166 if (type == JBStream::comp || type == JBStream::TypeCount) 02167 getStreamList(list[JBStream::comp],JBStream::comp); 02168 if (type == JBStream::cluster || type == JBStream::TypeCount) 02169 getStreamList(list[JBStream::cluster],JBStream::cluster); 02170 } 02171 02178 JBStream* findStream(const String& id, JBStreamSetList* list); 02179 02180 bool m_exiting; // Engine exiting flag 02181 JBRemoteDomainDef m_remoteDomain; // Default remote domain definition 02182 ObjList m_remoteDomains; // Remote domain definitions 02183 unsigned char m_restartMax; // Maximum value for stream restart counter 02184 unsigned int m_restartUpdInterval; // Update interval for stream restart counter 02185 unsigned int m_setupTimeout; // Overall stream setup timeout 02186 unsigned int m_startTimeout; // Wait stream start period 02187 unsigned int m_connectTimeout; // Outgoing: socket connect timeout 02188 unsigned int m_srvTimeout; // SRV query timeout 02189 unsigned int m_pingInterval; // Stream idle interval (no data received) 02190 unsigned int m_pingTimeout; // Sent ping timeout 02191 unsigned int m_idleTimeout; // Stream idle timeout (nothing sent or received) 02192 unsigned int m_pptTimeoutC2s; // Client streams postpone termination intervals 02193 unsigned int m_pptTimeout; // Non client streams postpone stream termination intervals 02194 unsigned int m_streamReadBuffer; // Stream read buffer length 02195 unsigned int m_maxIncompleteXml; // Maximum length of an incomplete xml 02196 bool m_hasClientTls; // True if TLS is available for outgoing streams 02197 int m_printXml; // Print XML data to output 02198 bool m_initialized; // True if already initialized 02199 02200 private: 02201 // Add/remove a connect stream thread when started/stopped 02202 void connectStatus(JBConnect* conn, bool started); 02203 // Stop a connect stream 02204 void stopConnect(const String& name); 02205 02206 ObjList m_connect; // Connecting streams 02207 }; 02208 02213 class YJABBER_API JBServerEngine : public JBEngine 02214 { 02215 YCLASS(JBServerEngine,JBEngine) 02216 public: 02221 JBServerEngine(const char* name = "jbserverengine"); 02222 02226 ~JBServerEngine(); 02227 02233 virtual void cleanup(bool final = false, bool waitTerminate = true); 02234 02240 virtual void buildStreamName(String& name, const JBStream* stream) 02241 { name << "stream/" << getStreamIndex(); } 02242 02254 JBServerStream* findServerStream(const String& local, const String& remote, bool out, 02255 bool auth = true); 02256 02267 JBServerStream* createServerStream(const String& local, const String& remote, 02268 const char* dbId = 0, const char* dbKey = 0, bool dbOnly = false, 02269 const NamedList* params = 0); 02270 02279 JBServerStream* createCompStream(const String& name, const String& local, const String& remote, 02280 const NamedList* params = 0); 02281 02289 JBClusterStream* findClusterStream(const String& remote, JBClusterStream* skip = 0); 02290 02299 virtual JBClusterStream* createClusterStream(const String& local, 02300 const String& remote, const NamedList* params = 0); 02301 02310 unsigned int terminateClientStreams(const JabberID& jid, 02311 XMPPError::Type error = XMPPError::NoError, const char* reason = 0); 02312 02313 protected: 02318 virtual void addStream(JBStream* stream); 02319 02326 virtual void removeStream(JBStream* stream, bool delObj = true); 02327 02332 virtual void stopStreamSets(bool waitTerminate = true); 02333 02339 virtual void getStreamList(RefPointer<JBStreamSetList>& list, int type); 02340 02347 virtual void getStreamListsType(int type, RefPointer<JBStreamSetList>& recv, 02348 RefPointer<JBStreamSetList>& process); 02349 02354 inline unsigned int getStreamIndex() { 02355 Lock lock(this); 02356 return ++m_streamIndex; 02357 } 02358 02359 unsigned int m_streamIndex; // Index used to build stream name 02360 JBStreamSetList* m_c2sReceive; // c2s streams receive list 02361 JBStreamSetList* m_c2sProcess; // c2s streams process list 02362 JBStreamSetList* m_s2sReceive; // s2s streams receive list 02363 JBStreamSetList* m_s2sProcess; // s2s streams process list 02364 JBStreamSetList* m_compReceive; // comp streams receive list 02365 JBStreamSetList* m_compProcess; // comp streams process list 02366 JBStreamSetList* m_clusterReceive; // cluster streams receive list 02367 JBStreamSetList* m_clusterProcess; // cluster streams process list 02368 }; 02369 02374 class YJABBER_API JBClientEngine : public JBEngine 02375 { 02376 YCLASS(JBClientEngine,JBEngine) 02377 public: 02382 JBClientEngine(const char* name = "jbclientengine"); 02383 02387 ~JBClientEngine(); 02388 02394 virtual void cleanup(bool final = false, bool waitTerminate = true); 02395 02401 JBClientStream* findAccount(const String& account); 02402 02410 JBClientStream* create(const String& account, const NamedList& params, 02411 const String& name = String::empty()); 02412 02418 virtual void getStreamList(RefPointer<JBStreamSetList>& list, int type); 02419 02420 protected: 02425 virtual void addStream(JBStream* stream); 02426 02433 virtual void removeStream(JBStream* stream, bool delObj = true); 02434 02439 virtual void stopStreamSets(bool waitTerminate = true); 02440 02441 JBStreamSetList* m_receive; // Streams receive list 02442 JBStreamSetList* m_process; // Streams process list 02443 }; 02444 02451 class YJABBER_API JBStreamSet : public GenObject, public Mutex 02452 { 02453 YCLASS(JBStreamSet,GenObject); 02454 friend class JBStreamSetList; 02455 public: 02459 virtual ~JBStreamSet(); 02460 02466 inline ObjList& clients() 02467 { return m_clients; } 02468 02475 virtual bool add(JBStream* client); 02476 02484 virtual bool remove(JBStream* client, bool delObj = true); 02485 02494 unsigned int dropAll(const JabberID& local = JabberID::empty(), 02495 const JabberID& remote = JabberID::empty(), 02496 XMPPError::Type error = XMPPError::NoError, const char* reason = 0); 02497 02502 void run(); 02503 02508 virtual bool start(); 02509 02513 virtual void stop(); 02514 02515 protected: 02520 JBStreamSet(JBStreamSetList* owner); 02521 02529 virtual bool process(JBStream& stream) = 0; 02530 02531 bool m_changed; // List changed flag 02532 bool m_exiting; // The thread is exiting (don't accept clients) 02533 JBStreamSetList* m_owner; // The list owning this set 02534 ObjList m_clients; // The streams list 02535 02536 private: 02537 JBStreamSet() {} // Private default constructor (forbidden) 02538 }; 02539 02540 02545 class YJABBER_API JBStreamSetProcessor : public JBStreamSet 02546 { 02547 YCLASS(JBStreamSetProcessor,JBStreamSet); 02548 protected: 02553 inline JBStreamSetProcessor(JBStreamSetList* owner) 02554 : JBStreamSet(owner) 02555 {} 02556 02565 virtual bool process(JBStream& stream); 02566 }; 02567 02568 02573 class YJABBER_API JBStreamSetReceive : public JBStreamSet 02574 { 02575 YCLASS(JBStreamSetReceive,JBStreamSet); 02576 protected: 02581 JBStreamSetReceive(JBStreamSetList* owner); 02582 02590 virtual bool process(JBStream& stream); 02591 02592 protected: 02593 DataBlock m_buffer; // Read buffer 02594 }; 02595 02596 02602 class YJABBER_API JBStreamSetList : public RefObject, public Mutex 02603 { 02604 YCLASS(JBStreamSetList,RefObject); 02605 friend class JBStreamSet; 02606 public: 02614 JBStreamSetList(JBEngine* engine, unsigned int max, unsigned int sleepMs, 02615 const char* name); 02616 02622 inline ObjList& sets() 02623 { return m_sets; } 02624 02628 virtual ~JBStreamSetList(); 02629 02634 inline unsigned int maxStreams() const 02635 { return m_max; } 02636 02641 inline unsigned int streamCount() const 02642 { return m_streamCount; } 02643 02648 inline JBEngine* engine() const 02649 { return m_engine; } 02650 02656 bool add(JBStream* client); 02657 02664 void remove(JBStream* client, bool delObj = true); 02665 02671 void stop(JBStreamSet* set = 0, bool waitTerminate = true); 02672 02677 virtual const String& toString() const; 02678 02679 protected: 02683 virtual void destroyed(); 02684 02689 void remove(JBStreamSet* set); 02690 02695 virtual JBStreamSet* build(); 02696 02697 JBEngine* m_engine; // The engine owning this list 02698 String m_name; // List name 02699 unsigned int m_max; // The maximum number of streams per set 02700 unsigned int m_sleepMs; // Time to sleep if nothig processed 02701 ObjList m_sets; // The sets list 02702 02703 private: 02704 JBStreamSetList() {} // Private default constructor (forbidden) 02705 02706 unsigned int m_streamCount; // Current number of streams in this list 02707 }; 02708 02709 02715 class YJABBER_API JBEntityCaps : public String 02716 { 02717 YCLASS(JBEntityCaps,String); 02718 public: 02722 enum { 02723 Ver1_3 = 1, // Version lower then 1.4 (m_data is the node version + advertised extensions) 02724 Ver1_4 = 2, // Version 1.4 or greater (m_data is the SHA-1 hash of features and identities) 02725 }; 02726 02734 inline JBEntityCaps(const char* id, char version, const char* node, const char* data) 02735 : String(id), 02736 m_version(version), m_node(node), m_data(data) 02737 {} 02738 02743 inline bool hasAudio() { 02744 return m_features.get(XMPPNamespace::JingleAppsRtpAudio) || 02745 m_features.get(XMPPNamespace::JingleAudio) || 02746 m_features.get(XMPPNamespace::JingleVoiceV1); 02747 } 02748 02757 static inline void buildId(String& buf, char version, const char* node, 02758 const char* data, String* ext = 0) 02759 { buf << (int)version << node << data << (ext ? ext->c_str() : ""); } 02760 02761 char m_version; 02762 String m_node; 02763 String m_data; 02764 XMPPFeatureList m_features; 02765 02766 private: 02767 JBEntityCaps() {} 02768 }; 02769 02770 02776 class YJABBER_API JBEntityCapsList : public ObjList, public Mutex 02777 { 02778 YCLASS(JBEntityCapsList,ObjList); 02779 public: 02783 inline JBEntityCapsList() 02784 : Mutex(true,"JBEntityCapsList"), m_enable(true), m_reqIndex(0) 02785 { m_reqPrefix << "xep0115" << (unsigned int)Time::msecNow() << "_"; } 02786 02792 inline JBEntityCaps* findCaps(const String& id) { 02793 for (ObjList* o = skipNull(); o; o = o->skipNext()) 02794 if (o->get()->toString() == id) 02795 return static_cast<JBEntityCaps*>(o->get()); 02796 return 0; 02797 } 02798 02804 void expire(u_int64_t msecNow = Time::msecNow()); 02805 02814 bool processRsp(XmlElement* rsp, const String& id, bool ok); 02815 02827 void requestCaps(JBStream* stream, const char* from, const char* to, const String& id, 02828 char version, const char* node, const char* data); 02829 02836 XmlDocument* toDocument(const char* rootName = "entitycaps"); 02837 02845 void fromDocument(XmlDocument& doc, const char* rootName = "entitycaps"); 02846 02859 virtual bool processCaps(String& capsId, XmlElement* xml, JBStream* stream, 02860 const char* from, const char* to); 02861 02868 inline void addCaps(NamedList& list, const String& id) { 02869 Lock lock(this); 02870 JBEntityCaps* caps = findCaps(id); 02871 if (caps) 02872 addCaps(list,*caps); 02873 } 02874 02881 virtual void addCaps(NamedList& list, JBEntityCaps& caps); 02882 02890 bool loadXmlDoc(const char* file, DebugEnabler* enabler = 0); 02891 02899 bool saveXmlDoc(const char* file, DebugEnabler* enabler = 0); 02900 02910 static bool decodeCaps(const XmlElement& xml, char& version, String*& node, 02911 String*& ver, String*& ext); 02912 02916 bool m_enable; 02917 02918 protected: 02924 virtual void capsAdded(JBEntityCaps* caps) 02925 {} 02926 02927 unsigned int m_reqIndex; // Disco info request index 02928 String m_reqPrefix; // Prefix for disco info stanza id 02929 ObjList m_requests; // List of sent disco info requests 02930 }; 02931 02932 }; // namespace TelEngine 02933 02934 #endif /* __YATEJABBER_H */ 02935 02936 /* vi: set ts=8 sw=4 sts=4 noet: */