1 /** 2 * yatejabber.h 3 * Yet Another Jabber Stack 4 * This file is part of the YATE Project http://YATE.null.ro 5 * 6 * Yet Another Telephony Engine - a fully featured software PBX and IVR 7 * Copyright (C) 2004-2014 Null Team 8 * 9 * This software is distributed under multiple licenses; 10 * see the COPYING file in the main directory for licensing 11 * information for this specific distribution. 12 * 13 * This use of this software may be subject to additional restrictions. 14 * See the LEGAL file in the main directory for details. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 19 */ 20 21 #ifndef __YATEJABBER_H 22 #define __YATEJABBER_H 23 24 #include <xmpputils.h> 25 26 /** 27 * Holds all Telephony Engine related classes. 28 */ 29 namespace TelEngine { 30 31 class SASL; // SASL authentication mechanism 32 class JBEvent; // A Jabber event 33 class JBStream; // A Jabber stream 34 class JBClientStream; // A client to server stream 35 class JBServerStream; // A server to server stream 36 class JBClusterStream; // A cluster stream 37 class JBRemoteDomainDef; // Options and connect settings for a remote domain 38 class JBConnect; // A socket connector 39 class JBEngine; // A Jabber engine 40 class JBServerEngine; // A Jabber server engine 41 class JBClientEngine; // A Jabber client engine 42 class JBStreamSet; // A set of streams to be processed in an uniform way 43 class JBStreamSetProcessor; // Specialized stream processor 44 class JBStreamSetReceive; // Specialized stream data receiver 45 class JBStreamSetList; // A list of stream sets 46 class JBEntityCaps; // Entity capability 47 class JBEntityCapsList; // Entity capability list manager 48 49 50 /** 51 * Default port for client to server connections 52 */ 53 #define XMPP_C2S_PORT 5222 54 55 /** 56 * Default port for server to server connections 57 */ 58 #define XMPP_S2S_PORT 5269 59 60 /** 61 * Default value for maximum length of an incomplete xml allowed in a stream 62 * parser's buffer 63 */ 64 #define XMPP_MAX_INCOMPLETEXML 8192 65 66 67 /** 68 * This class handles PLAIN (rfc 4616) and DIGEST (rfc 2831) SASL authentication 69 * @short SASL authentication mechanism 70 */ 71 class YJABBER_API SASL : public GenObject 72 { 73 YCLASS(SASL,GenObject) 74 public: 75 /** 76 * Constructor 77 * @param plain True to build a plain password auth object 78 * @param realm Optional server realm 79 */ 80 SASL(bool plain, const char* realm = 0); 81 82 /** 83 * Destructor 84 */ ~SASL()85 ~SASL() 86 { TelEngine::destruct(m_params); } 87 88 /** 89 * Set auth params 90 * @param user Optional username 91 * @param pwd Optional password 92 */ 93 void setAuthParams(const char* user = 0, const char* pwd = 0); 94 95 /** 96 * Build a client initial auth or challenge response 97 * @param buf Destination buffer. It will be filled with Base64 encoded result 98 * @param digestUri Digest MD5 URI 99 * @return True on success 100 */ 101 bool buildAuthRsp(String& buf, const char* digestUri = 0); 102 103 /** 104 * Build a server reply to challenge response 105 * @param buf Destination buffer. It will be filled with Base64 encoded result 106 * @param rsp The response 107 */ buildAuthRspReply(String & buf,const String & rsp)108 inline void buildAuthRspReply(String& buf, const String& rsp) { 109 if (m_plain) 110 return; 111 String tmp("rspauth=" + rsp); 112 Base64 b((void*)tmp.c_str(),tmp.length(),false); 113 b.encode(buf); 114 b.clear(false); 115 } 116 117 /** 118 * Check if a challenge response reply is valid 119 * @param reply The reply to check 120 * @return True if valid 121 */ validAuthReply(const String & reply)122 inline bool validAuthReply(const String& reply) { 123 String tmp; 124 if (m_params) 125 buildMD5Digest(tmp,m_params->getValue("password"),false); 126 return tmp == reply; 127 } 128 129 /** 130 * Build an MD5 challenge from this object. 131 * Generate a new nonce and increase nonce count 132 * @param buf Destination buffer 133 * @return True on success 134 */ 135 bool buildMD5Challenge(String& buf); 136 137 /** 138 * Build a Digest MD5 SASL (RFC 2831) to be sent with authentication responses 139 * @param dest Destination string 140 * @param password The password to use 141 * @param challengeRsp True if building a Digest MD5 challenge response, false if 142 * building a challenge response reply 143 */ 144 inline void buildMD5Digest(String& dest, const char* password, 145 bool challengeRsp = true) { 146 if (m_params) 147 buildMD5Digest(dest,*m_params,password,challengeRsp); 148 } 149 150 /** 151 * Parse plain password auth data 152 * @param buf The buffer to parse 153 * @return True if succesfully parsed 154 */ 155 bool parsePlain(const DataBlock& buf); 156 157 /** 158 * Parse and decode a buffer containing a SASL Digest MD5 challenge. 159 * @param buf Already checked for valid UTF8 characters input string 160 * @return True on success 161 */ 162 bool parseMD5Challenge(const String& buf); 163 164 /** 165 * Parse and decode a buffer containing a SASL Digest MD5 response. 166 * Check realm, nonce and nonce count 167 * @param buf Already checked for valid UTF8 characters input string 168 * @return True on success 169 */ 170 bool parseMD5ChallengeRsp(const String& buf); 171 172 /** 173 * Parse and decode a buffer containing SASL plain authentication data 174 * as defined in RFC 4616 175 * @param buf Input buffer 176 * @param user Destination buffer for username part 177 * @param pwd Destination buffer for password part 178 * @param authzid Optional destination buffer for authorization identity part 179 * @return True on success 180 */ 181 static bool parsePlain(const DataBlock& buf, String& user, String& pwd, 182 String* authzid = 0); 183 184 /** 185 * Build a Digest MD5 SASL (RFC 2831) to be sent with authentication responses 186 * @param dest Destination string 187 * @param params List of parameters 188 * @param password The password to use 189 * @param challengeRsp True if building a Digest MD5 challenge response, false if 190 * building a challenge response reply 191 */ 192 static void buildMD5Digest(String& dest, const NamedList& params, 193 const char* password, bool challengeRsp = true); 194 195 bool m_plain; 196 NamedList* m_params; 197 String m_realm; 198 String m_nonce; 199 String m_cnonce; 200 unsigned int m_nonceCount; 201 202 private: SASL()203 SASL() {} 204 }; 205 206 207 /** 208 * This class holds a Jabber stream event. Stream events are raised by streams 209 * and sent by the engine to the proper service 210 * @short A Jabber stream event 211 */ 212 class YJABBER_API JBEvent : public RefObject 213 { 214 YCLASS(JBEvent,RefObject) 215 friend class JBStream; 216 friend class JBClientStream; 217 friend class JBServerStream; 218 public: 219 /** 220 * Event type enumeration 221 */ 222 enum Type { 223 // Stream terminated. Try to connect or wait to be destroyed 224 Terminated, 225 // Stream is destroying 226 Destroy, 227 // Stream start was received: when processing this event, the upper 228 // layer must call stream's start() method or terminate the stream 229 Start, 230 // Incoming stream need auth: when processing this event, the upper 231 // layer must call stream's authenticated() method 232 // Component: the event's text contains the handshake data 233 Auth, 234 // The event's element is an 'iq' with a child qualified by bind namespace 235 // This event is generated by an incoming client stream without a bound resource 236 Bind, 237 // Stream is running (can send/recv stanzas) 238 Running, 239 // The event's element is a 'message' 240 Message, 241 // The event's element is a 'presence' 242 Presence, 243 // The event's element is an 'iq' 244 Iq, 245 // The event's element is a 'db:result' one received by a server-to-server stream 246 // containing the dialback key to verify 247 // The event's text is filled with dialback key to verify 248 DbResult, 249 // The event's element is a 'db:verify' one received by a server-to-server stream 250 DbVerify, 251 // New user register or user password change succeeded 252 RegisterOk, 253 // New user register or user password change failed 254 // The event's element is the response 255 RegisterFailed, 256 // Non stanza element received in Running state 257 Unknown 258 }; 259 260 /** 261 * Constructor. Constructs an event from a stream 262 * @param type Type of this event 263 * @param stream The stream that generated the event 264 * @param element Element that generated the event 265 * @param from Already parsed source JID 266 * @param to Already parsed destination JID 267 * @param child Optional type depending element's child 268 */ 269 inline JBEvent(Type type, JBStream* stream, XmlElement* element, 270 const JabberID& from, const JabberID& to, XmlElement* child = 0) m_type(type)271 : m_type(type), m_stream(0), m_link(true), m_element(element), 272 m_child(child) 273 { init(stream,element,&from,&to); } 274 275 /** 276 * Constructor. Constructs an event from a stream 277 * @param type Type of this event 278 * @param stream The stream that generated the event 279 * @param element Element that generated the event 280 * @param child Optional type depending element's child 281 */ 282 inline JBEvent(Type type, JBStream* stream, XmlElement* element, 283 XmlElement* child = 0) m_type(type)284 : m_type(type), m_stream(0), m_link(true), m_element(element), 285 m_child(child) 286 { init(stream,element); } 287 288 /** 289 * Destructor. Delete the XML element if valid 290 */ 291 virtual ~JBEvent(); 292 293 /** 294 * Get the event type 295 * @return The type of this event as enumeration 296 */ type()297 inline int type() const 298 { return m_type; } 299 300 /** 301 * Get the event name 302 * @return The name of this event 303 */ name()304 inline const char* name() const 305 { return lookup(type()); } 306 307 /** 308 * Get the element's 'type' attribute if any 309 * @return The element's 'type' attribute 310 */ stanzaType()311 inline const String& stanzaType() const 312 { return m_stanzaType; } 313 314 /** 315 * Get the 'from' attribute of a received stanza 316 * @return The 'from' attribute 317 */ from()318 inline const JabberID& from() const 319 { return m_from; } 320 321 /** 322 * Get the 'to' attribute of a received stanza 323 * @return The 'to' attribute 324 */ to()325 inline const JabberID& to() const 326 { return m_to; } 327 328 /** 329 * Get the sender's id for Write... events or the 'id' attribute if the 330 * event carries a received stanza 331 * @return The event id 332 */ id()333 inline const String& id() const 334 { return m_id; } 335 336 /** 337 * The stanza's text or termination reason for Terminated/Destroy events 338 * @return The event's text 339 */ text()340 inline const String& text() const 341 { return m_text; } 342 343 /** 344 * Get the stream that generated this event 345 * @return The stream that generated this event 346 */ stream()347 inline JBStream* stream() const 348 { return m_stream; } 349 350 /** 351 * Get a client-to-server stream from the event's stream 352 * @return JBClientStream pointer or 0 353 */ 354 JBClientStream* clientStream(); 355 356 /** 357 * Get a server-to-server stream from the event's stream 358 * @return JBServerStream pointer or 0 359 */ 360 JBServerStream* serverStream(); 361 362 /** 363 * Get a cluster stream from event's stream 364 * @return JBClusterStream pointer or 0 365 */ 366 JBClusterStream* clusterStream(); 367 368 /** 369 * Get the underlying XmlElement 370 * @return XmlElement pointer or 0 371 */ element()372 inline XmlElement* element() const 373 { return m_element; } 374 375 /** 376 * Get the first child of the underlying element if any 377 * @return XmlElement pointer or 0 378 */ child()379 inline XmlElement* child() const 380 { return m_child; } 381 382 /** 383 * Delete the underlying XmlElement(s). Release the ownership. 384 * The caller will own the returned pointer 385 * @param del True to delete all xml elements owned by this event 386 * @return XmlElement pointer if not deleted or 0 387 */ 388 XmlElement* releaseXml(bool del = false); 389 390 /** 391 * Build an 'iq' result stanza from event data 392 * @param addTags True to add the 'from' and 'to' attributes 393 * @param child Optional 'iq' child (will be consumed) 394 * @return True on success 395 */ 396 XmlElement* buildIqResult(bool addTags, XmlElement* child = 0); 397 398 /** 399 * Build and send a stanza 'result' from enclosed 'iq' element 400 * Release the element on success 401 * @param child Optional 'iq' child (will be consumed) 402 * @return True on success 403 */ 404 bool sendIqResult(XmlElement* child = 0); 405 406 /** 407 * Build an 'iq' error stanza from event data 408 * The event's element will be released and added to the error one 409 * if the id is empty 410 * @param addTags True to add the 'from' and 'to' attributes 411 * @param error Error to be returned to the event's XML sender 412 * @param reason Optional text to be attached to the error 413 * @param type Error type 414 * @return True on success 415 */ 416 XmlElement* buildIqError(bool addTags, XMPPError::Type error, const char* reason = 0, 417 XMPPError::ErrorType type = XMPPError::TypeModify); 418 419 /** 420 * Build and send a stanza error from enclosed element 421 * Release the element on success 422 * @param error Error to be returned to the event's XML sender 423 * @param reason Optional text to be attached to the error 424 * @param type Error type 425 * @return True on success 426 */ 427 bool sendStanzaError(XMPPError::Type error, const char* reason = 0, 428 XMPPError::ErrorType type = XMPPError::TypeModify); 429 430 /** 431 * Release the link with the stream to let the stream continue with events 432 * @param release True to release the reference to the stream 433 */ 434 void releaseStream(bool release = false); 435 436 /** 437 * Get the name of an event type 438 * @return The name an event type 439 */ lookup(int type)440 inline static const char* lookup(int type) 441 { return TelEngine::lookup(type,s_type); } 442 443 private: 444 static const TokenDict s_type[]; // Event names JBEvent()445 JBEvent() {} // Don't use it! 446 bool init(JBStream* stream, XmlElement* element, 447 const JabberID* from = 0, const JabberID* to = 0); 448 449 Type m_type; // Type of this event 450 JBStream* m_stream; // The stream that generated this event 451 bool m_link; // Stream link state 452 XmlElement* m_element; // Received XML element, if any 453 XmlElement* m_child; // The first child element for 'iq' elements 454 String m_stanzaType; // Stanza's 'type' attribute 455 JabberID m_from; // Stanza's 'from' attribute 456 JabberID m_to; // Stanza's 'to' attribute 457 String m_id; // 'id' attribute if the received element has one 458 String m_text; // The stanza's text or termination reason for 459 // Terminated/Destroy events 460 }; 461 462 463 /** 464 * Base class for all Jabber streams. Basic stream data processing: send/receive 465 * XML elements, keep stream state, generate events 466 * @short A Jabber stream 467 */ 468 class YJABBER_API JBStream : public RefObject, public DebugEnabler, public Mutex 469 { 470 friend class JBEngine; 471 friend class JBEvent; 472 public: 473 /** 474 * Stream type enumeration 475 */ 476 enum Type { 477 c2s = 0, // Client to server 478 s2s, // Server to server 479 comp, // External component 480 cluster, // Cluster stream 481 TypeCount // Unknown 482 }; 483 484 /** 485 * Stream state enumeration 486 */ 487 enum State { 488 Idle = 0, // Stream is waiting to be connected or destroyed 489 Connecting, // Outgoing stream is waiting for the socket to connect 490 WaitStart, // Waiting for remote's stream start 491 // (outgoing: stream start already sent) 492 Starting, // Incoming stream is processing a stream start element 493 Features, // Outgoing: waiting for stream features 494 // Incoming: stream features sent 495 WaitTlsRsp, // 'starttls' sent: waiting for response 496 Securing, // Stream is currently negotiating the TLS 497 Auth, // Auth element (db:result for s2s streams) sent 498 // Incoming comp: handshake received 499 Challenge, // 'challenge' element sent/received 500 Compressing, // Stream is negotiating compression 501 // outgoing: compress element sent, wait for response 502 // incoming: waiting for <compressed> element to be sent 503 Register, // A new user is currently registering 504 // Keep Running state here: we expect all other states 505 // (except for Destroy) to have lower values 506 Running, // Established. Allow XML stanzas to pass over the stream 507 Destroy, // Stream is destroying. No more traffic allowed 508 }; 509 510 /** 511 * Stream behaviour options 512 */ 513 enum Flags { 514 NoAutoRestart = 0x00000001,// Don't restart stream when down 515 TlsRequired = 0x00000002,// TLS is mandatory on this stream 516 AllowPlainAuth = 0x00000004,// Allow plain password authentication 517 // If not allowed and this is the only method 518 // offered by server the stream will be terminated 519 DialbackOnly = 0x00000008,// Outgoing s2s dialback stream 520 RegisterUser = 0x00000010,// Outgoing c2s register new user 521 Compress = 0x00000020,// Offer/handle compression 522 InError = 0x00000080,// The stream was terminated with error 523 // Flags to be managed by the upper layer 524 RosterRequested = 0x00000100,// c2s: the roster was already requested 525 AvailableResource = 0x00000200,// c2s: available presence was sent/received 526 PositivePriority = 0x00000400,// c2s: the resource advertised by the client has priority >= 0 527 // Internal flags (cleared when the stream is re-started) 528 SetCompressed = 0x00010000,// Set StreamCompressed flag after succesfully sending 529 // the current stream xml buffer 530 StreamSecured = 0x00020000,// TLS stage was done (possible without using TLS) 531 StreamTls = 0x00040000,// The stream is using TLS 532 StreamAuthenticated = 0x00080000,// Stream already authenticated 533 StreamRemoteVer1 = 0x00100000,// Remote party advertised RFC3920 version=1.0 534 StreamLocalVer1 = 0x00200000,// Advertise RFC3920 version=1.0 on incoming streams 535 StreamWaitBindRsp = 0x01000000,// Outgoing c2s waiting for bind response 536 StreamWaitSessRsp = 0x02000000,// Outgoing c2s waiting for session response 537 StreamWaitChallenge = 0x04000000,// Outgoing waiting for auth challenge 538 StreamWaitChgRsp = 0x08000000,// Outgoing waiting challenge response confirmation 539 StreamRfc3920Chg = 0x10000000,// Outgoing sent empty response to challenge with rspauth (RFC3920) 540 StreamCompressed = 0x20000000,// The stream is using compression 541 StreamCanCompress = 0x40000000,// Incoming s2s may still be compressed 542 // Flag masks 543 StreamFlags = 0x000000ff, 544 InternalFlags = 0xffff0000, 545 }; 546 547 /** 548 * Destructor. 549 * Gracefully close the stream and the socket 550 */ 551 virtual ~JBStream(); 552 553 /** 554 * Get the type of this stream. See the protocol enumeration of the engine 555 * @return The type of this stream 556 */ type()557 inline int type() const 558 { return m_type; } 559 560 /** 561 * Retrieve this stream's default namespace 562 * @return The stream default namespace 563 */ xmlns()564 inline int xmlns() const 565 { return m_xmlns; } 566 567 /** 568 * Get the stream state 569 * @return The stream state as enumeration. 570 */ state()571 inline State state() const 572 { return m_state; } 573 574 /** 575 * Get the stream direction 576 * @return True if the stream is an incoming one 577 */ incoming()578 inline bool incoming() const 579 { return m_incoming; } 580 581 /** 582 * Get the stream direction 583 * @return True if the stream is an outgoing one 584 */ outgoing()585 inline bool outgoing() const 586 { return !m_incoming; } 587 588 /** 589 * Get the stream's owner 590 * @return Pointer to the engine owning this stream 591 */ engine()592 inline JBEngine* engine() const 593 { return m_engine; } 594 595 /** 596 * Get the stream's name 597 * @return The stream's name 598 */ name()599 inline const char* name() const 600 { return m_name; } 601 602 /** 603 * Get the stream id 604 * @return The stream id 605 */ id()606 inline const String& id() const 607 { return m_id; } 608 609 /** 610 * Check if the stream id equals a given string. 611 * This method is thread safe 612 * @param str The string to check 613 * @return True if the given string equals this stream's id 614 */ isId(const String & str)615 inline bool isId(const String& str) { 616 Lock lock(this); 617 return str == m_id; 618 } 619 620 /** 621 * Get the JID of the local side of this stream 622 * @return The JID of the local side of this stream 623 */ local()624 inline const JabberID& local() const 625 { return m_local; } 626 627 /** 628 * Get the JID of the local side of this stream. 629 * This method is thread safe 630 * @param jid The JID to be filled with the local side of this stream 631 */ local(JabberID & jid)632 inline void local(JabberID& jid) { 633 Lock lock(this); 634 jid = m_local; 635 } 636 637 /** 638 * Set the local party's JID 639 * @param jid Local party's jid to set 640 */ setLocal(const char * jid)641 inline void setLocal(const char* jid) 642 { m_local.set(jid); } 643 644 /** 645 * Get the JID of the remote side of this stream 646 * @return The JID of the remote side of this stream 647 */ remote()648 inline const JabberID& remote() const 649 { return m_remote; } 650 651 /** 652 * Get the JID of the remote side of this stream. 653 * This method is thread safe 654 * @param jid The JID to be filled with the remote side of this stream 655 */ remote(JabberID & jid)656 inline void remote(JabberID& jid) { 657 Lock lock(this); 658 jid = m_remote; 659 } 660 661 /** 662 * Get the remote party's address 663 * This method is thread safe 664 * @param addr The socket address to be filled with remote party's address 665 * @return True on success 666 */ remoteAddr(SocketAddr & addr)667 inline bool remoteAddr(SocketAddr& addr) { 668 Lock lock(this); 669 return m_socket && m_socket->getPeerName(addr); 670 } 671 672 /** 673 * Get the local address 674 * This method is thread safe 675 * @param addr The socket address to be filled with local address 676 * @return True on success 677 */ localAddr(SocketAddr & addr)678 inline bool localAddr(SocketAddr& addr) { 679 Lock lock(this); 680 return m_socket && m_socket->getSockName(addr); 681 } 682 683 /** 684 * Get the stream flags 685 * @return Stream flags 686 */ flags()687 inline int flags() const 688 { return m_flags; } 689 690 /** 691 * Check if a given option (or option mask) is set 692 * @param mask The flag(s) to check 693 * @return True if set 694 */ flag(int mask)695 inline bool flag(int mask) const 696 { return 0 != (m_flags & mask); } 697 698 /** 699 * Set or reset the TLS required flag 700 * This method is not thread safe 701 * @param set True to set, false to reset the flag 702 */ setTlsRequired(bool set)703 inline void setTlsRequired(bool set) { 704 Lock lock(this); 705 if (set) 706 setFlags(TlsRequired); 707 else 708 resetFlags(TlsRequired); 709 } 710 711 /** 712 * Check if the stream has valid pending data (received xml elements in queue or 713 * pending events or pending xml elements that can still be sent). 714 * This method is thread safe 715 * @return True if the stream have pending data, false otherwise 716 */ 717 bool haveData(); 718 719 /** 720 * Retrieve connection address(es), port and status 721 * This method is not thread safe 722 * @param addr The remote ip 723 * @param port The remote port 724 * @param localip Local ip to bind 725 * @param stat Current connect status 726 * @param isRedirect Optional pointer to be set to true if returned address is a redirect one 727 * @param srvs List to copy stream SRV records 728 */ 729 void connectAddr(String& addr, int& port, String& localip, int& stat, 730 ObjList& srvs, bool* isRedirect = 0) const; 731 732 /** 733 * Retrieve server host when connecting. 734 * This method is not thread safe 735 * @return Server host if set, remote jid's domain otherwise 736 */ serverHost()737 inline const String& serverHost() const 738 { return m_serverHost ? m_serverHost : m_remote.domain(); } 739 740 /** 741 * Set/reset RosterRequested flag 742 * This method is thread safe 743 * @param ok True to set, false to reset it 744 */ 745 void setRosterRequested(bool ok); 746 747 /** 748 * Set/reset AvailableResource/PositivePriority flags 749 * This method is thread safe 750 * @param ok True to set, false to reset it 751 * @param positive True if an available resource has positive priority 752 * @return True if changed 753 */ 754 bool setAvailableResource(bool ok, bool positive = true); 755 756 /** 757 * Read data from socket. Send it to the parser. 758 * Terminate the stream on socket or parser error 759 * @param buf Destination buffer 760 * @param len Buffer length (must be greater then 1) 761 * @return True if data was received 762 */ 763 bool readSocket(char* buf, unsigned int len); 764 765 /** 766 * Get a client stream from this one 767 * @return JBClientStream pointer or 0 768 */ clientStream()769 virtual JBClientStream* clientStream() 770 { return 0; } 771 772 /** 773 * Get a server stream from this one 774 * @return JBServerStream pointer or 0 775 */ serverStream()776 virtual JBServerStream* serverStream() 777 { return 0; } 778 779 /** 780 * Get a cluster stream from this one 781 * @return JBClusterStream pointer 782 */ clusterStream()783 virtual JBClusterStream* clusterStream() 784 { return 0; } 785 786 /** 787 * Stream state processor. 788 * This method is thread safe 789 * @param time Current time 790 * @return JBEvent pointer or 0 791 */ 792 JBEvent* getEvent(u_int64_t time = Time::msecNow()); 793 794 /** 795 * Send a stanza ('iq', 'message' or 'presence') or dialback elements in Running state. 796 * This method is thread safe 797 * @param xml Element to send (will be consumed and zeroed) 798 * @return True on success 799 */ 800 bool sendStanza(XmlElement*& xml); 801 802 /** 803 * Send stream related XML when negotiating the stream or some other 804 * stanza in non Running state 805 * All elements will be consumed 806 * This method is thread safe 807 * @param newState The new stream state to set on success 808 * @param first The first element to send 809 * @param second Optional second element to send 810 * @param third Optional third element to send 811 * @return True on success 812 */ 813 bool sendStreamXml(State newState, XmlElement* first, XmlElement* second = 0, 814 XmlElement* third = 0); 815 816 /** 817 * Start the stream. This method should be called by the upper layer 818 * when processing an incoming stream Start event 819 * This method is thread safe 820 * @param features Optional features to advertise to the remote party of an 821 * incoming stream. The caller is responsable of freeing it. 822 * If processed, list's elements will be moved to stream's features list 823 * @param caps Optional entity capabilities to be added to the stream features. 824 * Ignored for outgoing streams 825 * @param useVer1 Advertise RFC3920 version. Ignored for outgoing streams 826 */ 827 void start(XMPPFeatureList* features = 0, XmlElement* caps = 0, bool useVer1 = true); 828 829 /** 830 * Auth event result. This method should be called by the 831 * upper layer when processing an Auth event 832 * This method is thread safe 833 * @param ok True if the remote party was authenticated, 834 * false if authentication failed 835 * @param rsp Optional success response content. Ignored if not authenticated 836 * @param error Failure reason. Ignored if authenticated 837 * @param username Authenticated user 838 * @param id Non SASL auth response id 839 * @param resource Client resource to set when non SASL authentication is used 840 * @return False if stream state is incorrect 841 */ 842 bool authenticated(bool ok, const String& rsp = String::empty(), 843 XMPPError::Type error = XMPPError::NotAuthorized, 844 const char* username = 0, const char* id = 0, const char* resource = 0); 845 846 /** 847 * Terminate the stream. Send stream end tag or error. 848 * Reset the stream. Deref stream if destroying. 849 * This method is thread safe 850 * @param location The terminate request location: 851 * -1: upper layer, 0: internal, 1: remote 852 * @param destroy True to destroy. False to terminate 853 * @param xml Received XML element. The element will be consumed 854 * @param error Termination reason. Set it to NoError to send stream end tag 855 * @param reason Optional text to be added to the error stanza 856 * @param final True if called from destructor 857 * @param genEvent True to generate terminated event 858 * @param content Optional sent error condition element text 859 */ 860 void terminate(int location, bool destroy, XmlElement* xml, 861 int error = XMPPError::NoError, const char* reason = "", 862 bool final = false, bool genEvent = true, const char* content = 0); 863 864 /** 865 * Outgoing stream connect terminated notification. 866 * Send stream start if everithing is ok 867 * @param sock The connected socket, will be consumed and zeroed 868 */ 869 virtual void connectTerminated(Socket*& sock); 870 871 /** 872 * Connecting notification. Start connect timer for synchronous connect 873 * This method is thread safe 874 * @param sync True if the connection is synchronous 875 * @param stat Current status of the connect thread 876 * @param srvs Current list of SRV records in the connect thread 877 * @return True if accepted 878 */ 879 virtual bool connecting(bool sync, int stat, ObjList& srvs); 880 881 /** 882 * Get an object from this stream 883 * @param name The name of the object to get 884 */ 885 virtual void* getObject(const String& name) const; 886 887 /** 888 * Get the name of a stream state 889 * @return The name of the stream state 890 */ stateName()891 inline const char* stateName() const 892 { return lookup(state(),s_stateName); } 893 894 /** 895 * Get the name of a stream type 896 * @return The name of the stream type 897 */ typeName()898 inline const char* typeName() const 899 { return lookup(type(),s_typeName); } 900 901 /** 902 * Build a SHA1 digest from stream id and secret 903 * @param buf Destination buffer 904 * @param secret The secret 905 */ buildSha1Digest(String & buf,const String & secret)906 inline void buildSha1Digest(String& buf, const String& secret) { 907 SHA1 sha(id() + secret); 908 buf = sha.hexDigest(); 909 buf.toLower(); 910 } 911 912 /** 913 * Get the string representation of this stream 914 * @return Stream name 915 */ 916 virtual const String& toString() const; 917 918 /** 919 * Get the stream type associated with a given text 920 * @param text Stream type text to find 921 * @param defVal Value to return if not found 922 * @return The stream type associated with a given text 923 */ 924 static inline Type lookupType(const char* text, Type defVal = TypeCount) 925 { return (Type)lookup(text,s_typeName,defVal); } 926 927 /** 928 * SASL authentication data 929 */ 930 SASL* m_sasl; 931 932 /** 933 * Dictionary keeping the stream state names 934 */ 935 static const TokenDict s_stateName[]; 936 937 /** 938 * Dictionary keeping the flag names 939 */ 940 static const TokenDict s_flagName[]; 941 942 /** 943 * Dictionary keeping the stream type names 944 */ 945 static const TokenDict s_typeName[]; 946 947 protected: 948 /** 949 * Constructor. Build an incoming stream from a socket 950 * @param engine Engine owning this stream 951 * @param socket The socket 952 * @param t Stream type as enumeration 953 * @param ssl True if the socket is already using SSL/TLS 954 */ 955 JBStream(JBEngine* engine, Socket* socket, Type t, bool ssl = false); 956 957 /** 958 * Constructor. Build an outgoing stream 959 * @param engine Engine owning this stream 960 * @param t Stream type as enumeration 961 * @param local Local party jabber id 962 * @param remote Remote party jabber id 963 * @param name Optional stream name 964 * @param params Optional stream parameters 965 * @param serverHost Optional server host to use instead of jid domain 966 */ 967 JBStream(JBEngine* engine, Type t, const JabberID& local, const JabberID& remote, 968 const char* name = 0, const NamedList* params = 0, const char* serverHost = 0); 969 970 /** 971 * Close the stream. Release memory 972 */ 973 virtual void destroyed(); 974 975 /** 976 * Check if stream state processor can continue. 977 * This method is called from getEvent() with the stream locked 978 * @param time Current time 979 * @return True to indicate stream availability to process its state, 980 * false to return the last event, if any 981 */ 982 virtual bool canProcess(u_int64_t time); 983 984 /** 985 * Process stream state. Get XML from parser's queue and process it 986 * This method is called from getEvent() with the stream locked 987 * @param time Current time 988 */ 989 virtual void process(u_int64_t time); 990 991 /** 992 * Process elements in Running state 993 * @param xml Received element (will be consumed) 994 * @param from Already parsed source JID 995 * @param to Already parsed destination JID 996 * @return False if stream termination was initiated 997 */ 998 virtual bool processRunning(XmlElement* xml, const JabberID& from, 999 const JabberID& to); 1000 1001 /** 1002 * Check stream timeouts. 1003 * This method is called from getEvent() with the stream locked, after 1004 * the process() method returned without setting the last event 1005 * @param time Current time 1006 */ 1007 virtual void checkTimeouts(u_int64_t time); 1008 1009 /** 1010 * Reset the stream's connection. Build a new XML parser if the socket is valid 1011 * Release the old connection 1012 * @param sock The new socket 1013 */ 1014 virtual void resetConnection(Socket* sock = 0); 1015 1016 /** 1017 * Build a ping iq stanza 1018 * @param stanzaId Stanza id 1019 * @return 0 1020 */ 1021 virtual XmlElement* buildPing(const String& stanzaId); 1022 1023 /** 1024 * Build a stream start XML element 1025 * @return XmlElement pointer 1026 */ 1027 virtual XmlElement* buildStreamStart(); 1028 1029 /** 1030 * Process stream start elements while waiting for them 1031 * @param xml Received xml element 1032 * @param from The 'from' attribute 1033 * @param to The 'to' attribute 1034 * @return False if stream termination was initiated 1035 */ 1036 virtual bool processStart(const XmlElement* xml, const JabberID& from, 1037 const JabberID& to); 1038 1039 /** 1040 * Process elements in Auth state 1041 * @param xml Received element (will be consumed) 1042 * @param from Already parsed source JID 1043 * @param to Already parsed destination JID 1044 * @return False if stream termination was initiated 1045 */ 1046 virtual bool processAuth(XmlElement* xml, const JabberID& from, 1047 const JabberID& to); 1048 1049 /** 1050 * Process elements in Compressing state 1051 * @param xml Received element (will be consumed) 1052 * @param from Already parsed source JID 1053 * @param to Already parsed destination JID 1054 * @return False if stream termination was initiated 1055 */ 1056 virtual bool processCompressing(XmlElement* xml, const JabberID& from, 1057 const JabberID& to); 1058 1059 /** 1060 * Process elements in Register state 1061 * @param xml Received element (will be consumed) 1062 * @param from Already parsed source JID 1063 * @param to Already parsed destination JID 1064 * @return False if stream termination was initiated 1065 */ 1066 virtual bool processRegister(XmlElement* xml, const JabberID& from, 1067 const JabberID& to); 1068 1069 /** 1070 * Check if a received stream start element is correct. 1071 * Check namespaces and set stream version 1072 * Check and set the id for outgoing streams 1073 * Generate an id for incoming streams 1074 * Terminate the stream if this conditions are met 1075 * @param xml Received xml element 1076 * @return False if stream termination was initiated 1077 */ 1078 bool processStreamStart(const XmlElement* xml); 1079 1080 /** 1081 * Handle an already checked (tag and namespace) compress request 1082 * Respond to it. Change stream state on success 1083 * @param xml Received xml element (will be consumed) 1084 * @return False if stream termination was initiated 1085 */ 1086 bool handleCompressReq(XmlElement* xml); 1087 1088 /** 1089 * Check if a received element is a stream error one 1090 * @param xml Received xml element 1091 * @return True if stream termination was initiated (the xml will be consumed) 1092 */ 1093 bool streamError(XmlElement* xml); 1094 1095 /** 1096 * Retrieve and check the 'from' and 'to' JIDs from a receive element 1097 * @param xml Received xml element 1098 * @param from Jabber ID to set from the 'from' attribute 1099 * @param to Jabber ID to set from the 'to' attribute 1100 * @return False if stream termination was initiated (the xml will be consumed) 1101 */ 1102 bool getJids(XmlElement* xml, JabberID& from, JabberID& to); 1103 1104 /** 1105 * Check if a received element is a presence, message or iq qualified by the stream 1106 * namespace and the stream is not authenticated. 1107 * Validate 'from' for c2s streams 1108 * Validate s2s 'to' domain and 'from' jid 1109 * Fix 'from' or 'to' is needed 1110 * @param xml Received xml element (will be consumed if false is returned) 1111 * @param from The sender of the stanza 1112 * @param to Stanza recipient 1113 * @return False if the element was consumed (error was sent or stream termination was initiated) 1114 */ 1115 bool checkStanzaRecv(XmlElement* xml, JabberID& from, JabberID& to); 1116 1117 /** 1118 * Change stream state. Reset state depending data 1119 * @param newState The new stream state 1120 * @param time Current time 1121 */ 1122 void changeState(State newState, u_int64_t time = Time::msecNow()); 1123 1124 /** 1125 * Check if the stream compress flag is set and compression was offered by remote party 1126 * @return Compress request XmlElement pointer or 0 1127 */ 1128 XmlElement* checkCompress(); 1129 1130 /** 1131 * Check for pending events. Set the last event 1132 */ 1133 void checkPendingEvent(); 1134 1135 /** 1136 * Send pending stream XML or stanzas 1137 * Terminate the stream on error 1138 * @param streamOnly Try to send only existing stream related XML elements 1139 * @return True on success 1140 */ 1141 bool sendPending(bool streamOnly = false); 1142 1143 /** 1144 * Write data to socket. Terminate the stream on socket error 1145 * @param data Buffer to sent 1146 * @param len The number of bytes to send. Filled with actually sent bytes on exit 1147 * @return True on success, false on failure 1148 */ 1149 bool writeSocket(const void* data, unsigned int& len); 1150 1151 /** 1152 * Update stream flags and remote connection data from engine 1153 */ 1154 void updateFromRemoteDef(); 1155 1156 /** 1157 * Retrieve the first required feature in the list 1158 * @return XMPPFeature pointer or 0 1159 */ 1160 XMPPFeature* firstRequiredFeature(); 1161 1162 /** 1163 * Drop (delete) received XML element 1164 * @param xml The element to delete 1165 * @param reason The reason 1166 * @return True 1167 */ 1168 bool dropXml(XmlElement*& xml, const char* reason); 1169 1170 /** 1171 * Terminate (destroy) the stream. Drop (delete) received XML element 1172 * @param xml The element to delete 1173 * @param error Terminate error 1174 * @param reason Drop reason 1175 * @return False 1176 */ destroyDropXml(XmlElement * & xml,XMPPError::Type error,const char * reason)1177 inline bool destroyDropXml(XmlElement*& xml, XMPPError::Type error, const char* reason) { 1178 dropXml(xml,reason); 1179 terminate(0,true,0,error); 1180 return false; 1181 } 1182 1183 /** 1184 * Set stream flag mask 1185 * @param mask The bit mask to set 1186 */ 1187 void setFlags(int mask); 1188 1189 /** 1190 * Reset stream flag mask 1191 * @param mask The bit mask to reset 1192 */ 1193 void resetFlags(int mask); 1194 1195 /** 1196 * Set secured flag. Remove feature from list 1197 */ setSecured()1198 inline void setSecured() { 1199 setFlags(StreamSecured); 1200 m_features.remove(XMPPNamespace::Tls); 1201 } 1202 1203 /** 1204 * Set the idle timer in Running state 1205 * @param msecNow Current time in milliseconds 1206 */ 1207 void setIdleTimer(u_int64_t msecNow = Time::msecNow()); 1208 1209 /** 1210 * Reset ping data 1211 */ 1212 void resetPing(); 1213 1214 /** 1215 * Set the time of the next ping if there is any timeout and we don't have a ping in progress. 1216 * Set the ping timeout if an element is returned 1217 * @param force True to set it even if already set 1218 * @return XmlElement containing the ping to send, 0 if no ping is going to be sent or 'force' is true 1219 */ 1220 XmlElement* setNextPing(bool force); 1221 1222 /** 1223 * Generate a stanza index from stream id and current stanza index 1224 * Set the ping timeout if an element is returned 1225 * @param buf Destination string 1226 * @param extra Optional extra string 1227 */ 1228 inline void generateIdIndex(String& buf, const char* extra = 0) 1229 { buf = id() + extra + String(++m_stanzaIndex); } 1230 1231 State m_state; // Stream state 1232 String m_id; // Stream id 1233 JabberID m_local; // Local peer's jid 1234 JabberID m_remote; // Remote peer's jid 1235 String m_serverHost; // Outgoing: optional server host (replaces remote domain when connecting) 1236 int m_flags; // Stream flags 1237 XMPPNamespace::Type m_xmlns; // Stream namespace 1238 XMPPFeatureList m_features; // Advertised features 1239 JBEvent* m_lastEvent; // Last event generated by this stream 1240 ObjList m_events; // Queued events 1241 ObjList m_pending; // Pending outgoing elements 1242 unsigned int m_stanzaIndex; // Index used to generate IDs for stanzas 1243 // Timers 1244 u_int64_t m_setupTimeout; // Overall stream setup timeout 1245 u_int64_t m_startTimeout; // Incoming: wait stream start period 1246 u_int64_t m_pingTimeout; // Sent ping timeout 1247 u_int64_t m_pingInterval; // Ping interval 1248 u_int64_t m_nextPing; // Next ping 1249 u_int64_t m_idleTimeout; // Stream idle timeout 1250 u_int64_t m_connectTimeout; // Stream connect timeout 1251 // 1252 unsigned int m_restart; // Remaining restarts 1253 u_int64_t m_timeToFillRestart; // The next time to increase the restart counter 1254 1255 String m_pingId; 1256 1257 private: 1258 // Forbidden default constructor JBStream()1259 inline JBStream() {} 1260 // Process incoming elements in Challenge state 1261 // The element will be consumed 1262 // Return false if stream termination was initiated 1263 bool processChallenge(XmlElement* xml, const JabberID& from, 1264 const JabberID& to); 1265 // Process incoming 'auth' elements qualified by SASL namespace 1266 // The element will be consumed 1267 // Return false if stream termination was initiated 1268 bool processSaslAuth(XmlElement* xml, const JabberID& from, 1269 const JabberID& to); 1270 // Process received elements in Features state (incoming stream) 1271 // The element will be consumed 1272 // Return false if stream termination was initiated 1273 bool processFeaturesIn(XmlElement* xml, const JabberID& from, 1274 const JabberID& to); 1275 // Process received elements in Features state (outgoing stream) 1276 // The element will be consumed 1277 // Return false if stream termination was initiated 1278 bool processFeaturesOut(XmlElement* xml, const JabberID& from, 1279 const JabberID& to); 1280 // Process received elements in WaitTlsRsp state (outgoing stream) 1281 // The element will be consumed 1282 // Return false if stream termination was initiated 1283 bool processWaitTlsRsp(XmlElement* xml, const JabberID& from, 1284 const JabberID& to); 1285 // Set stream namespace from type 1286 void setXmlns(); 1287 // Event termination notification 1288 // @param event The notifier. Ignored if it's not m_lastEvent 1289 void eventTerminated(const JBEvent* event); 1290 // Compress data to be sent (the pending stream xml buffer or pending stanza) 1291 // Return false on failure 1292 bool compress(XmlElementOut* xml = 0); 1293 // Reset connect status data 1294 void resetConnectStatus(); 1295 // Postpone stream terminate until all parsed elements are processed 1296 // Terminate now if allowed 1297 // This method is thread safe 1298 void postponeTerminate(int location, bool destroy, int error, const char* reason); 1299 // Handle postponed termination. Return true if found 1300 // This method is not thread safe 1301 bool postponedTerminate(); 1302 // Reset redirect data 1303 void setRedirect(const String& addr = String::empty(), int port = 0); 1304 // Reset postponed terminate data resetPostponedTerminate()1305 inline void resetPostponedTerminate() { 1306 m_ppTerminateTimeout = 0; 1307 TelEngine::destruct(m_ppTerminate); 1308 } 1309 1310 enum { 1311 SocketCanRead = 0x01, 1312 SocketReading = 0x02, 1313 SocketCanWrite = 0x10, 1314 SocketWriting = 0x20, 1315 SocketWaitReset = 0x80, 1316 }; socketSetCanRead(bool ok)1317 inline void socketSetCanRead(bool ok) { 1318 Lock lock(m_socketMutex); 1319 if (ok) 1320 m_socketFlags |= SocketCanRead; 1321 else 1322 m_socketFlags &= ~SocketCanRead; 1323 } socketSetReading(bool ok)1324 inline void socketSetReading(bool ok) { 1325 if (ok) 1326 m_socketFlags |= SocketReading; 1327 else 1328 m_socketFlags &= ~SocketReading; 1329 } socketSetCanWrite(bool ok)1330 inline void socketSetCanWrite(bool ok) { 1331 Lock lock(m_socketMutex); 1332 if (ok) 1333 m_socketFlags |= SocketCanWrite; 1334 else 1335 m_socketFlags &= ~SocketCanWrite; 1336 } socketSetWriting(bool ok)1337 inline void socketSetWriting(bool ok) { 1338 if (ok) 1339 m_socketFlags |= SocketWriting; 1340 else 1341 m_socketFlags &= ~SocketWriting; 1342 } socketCanRead()1343 inline bool socketCanRead() const { 1344 return m_socket && (m_socketFlags & SocketCanRead) && 1345 !socketWaitReset(); 1346 } socketCanWrite()1347 inline bool socketCanWrite() const { 1348 return m_socket && (m_socketFlags & SocketCanWrite) && 1349 !socketWaitReset(); 1350 } socketReading()1351 inline bool socketReading() const 1352 { return (m_socketFlags & SocketReading) != 0; } socketWriting()1353 inline bool socketWriting() const 1354 { return (m_socketFlags & SocketWriting) != 0; } socketWaitReset()1355 inline bool socketWaitReset() const 1356 { return 0 != (m_socketFlags & SocketWaitReset); } 1357 1358 JBEngine* m_engine; // The owner of this stream 1359 int m_type; // Stream type 1360 bool m_incoming; // Stream direction 1361 String m_name; // Local (internal) name 1362 JBEvent* m_terminateEvent; // Pending terminate event 1363 NamedList* m_ppTerminate; // Postponed terminate parameters 1364 u_int64_t m_ppTerminateTimeout; // Postponed terminate timeout 1365 // Pending outgoing XML 1366 String m_outStreamXml; 1367 DataBlock m_outStreamXmlCompress; 1368 DataBlock m_outXmlCompress; 1369 // Connection related data 1370 XmlDomParser* m_xmlDom; 1371 Socket* m_socket; 1372 char m_socketFlags; // Socket flags: 0: unavailable 1373 Mutex m_socketMutex; // Protect the socket and parser 1374 String m_connectAddr; // Remote ip to connect to 1375 int m_connectPort; // Remote port to connect to 1376 String m_localIp; // Local ip to bind when connecting 1377 Compressor* m_compress; 1378 int m_connectStatus; // Current connect stream status 1379 ObjList m_connectSrvs; // Current connect stream SRV records 1380 unsigned int m_redirectMax; 1381 unsigned int m_redirectCount; 1382 String m_redirectAddr; 1383 int m_redirectPort; 1384 }; 1385 1386 1387 /** 1388 * This class holds a client to server stream 1389 * @short A client to server stream 1390 */ 1391 class YJABBER_API JBClientStream : public JBStream 1392 { 1393 YCLASS(JBClientStream,JBStream) 1394 friend class JBStream; 1395 public: 1396 /** 1397 * Constructor. Build an incoming stream from a socket 1398 * @param engine Engine owning this stream 1399 * @param socket The socket 1400 * @param ssl True if the socket is already using SSL/TLS 1401 */ 1402 JBClientStream(JBEngine* engine, Socket* socket, bool ssl = false); 1403 1404 /** 1405 * Constructor. Build an outgoing stream 1406 * @param engine Engine owning this stream 1407 * @param jid User jid 1408 * @param account Account (stream) name 1409 * @param params Stream parameters 1410 * @param name Optional stream name 1411 * @param serverHost Optional server host to use instead of jid domain 1412 */ 1413 JBClientStream(JBEngine* engine, const JabberID& jid, const String& account, 1414 const NamedList& params, const char* name = 0, const char* serverHost = 0); 1415 1416 /** 1417 * Retrieve stream's account 1418 * @return Stream account 1419 */ account()1420 inline const String& account() const 1421 { return m_account; } 1422 1423 /** 1424 * Retrieve stream's user data 1425 * @return GenObject pointer or 0 1426 */ userData()1427 inline GenObject* userData() 1428 { return m_userData; } 1429 1430 /** 1431 * Set stream's user data. Transfer data ownership to the stream 1432 * This method is thread safe 1433 * @param data Data to set 1434 */ userData(GenObject * data)1435 inline void userData(GenObject* data) { 1436 Lock lock(this); 1437 TelEngine::destruct(m_userData); 1438 m_userData = data; 1439 } 1440 1441 /** 1442 * Get a client stream from this one 1443 * @return JBClientStream pointer 1444 */ clientStream()1445 virtual JBClientStream* clientStream() 1446 { return this; } 1447 1448 /** 1449 * Build a ping iq stanza 1450 * @param stanzaId Stanza id 1451 * @return Valid XmlElement pointer 1452 */ 1453 virtual XmlElement* buildPing(const String& stanzaId); 1454 1455 /** 1456 * Bind a resource to an incoming stream. This method should be called 1457 * after processing a Bind event 1458 * This method is thread safe 1459 * @param resource Resource to bind. Empty on error 1460 * @param id Received bind request id 1461 * @param error Failure reason. Ignored on success 1462 */ 1463 void bind(const String& resource, const char* id, 1464 XMPPError::Type error = XMPPError::NoError); 1465 1466 /** 1467 * Request account register or change on outgoing stream. 1468 * This method is thread safe 1469 * @param data True to request registration/change, false to request info 1470 * @param set True to request new user registration, false to remove account from server 1471 * @param newPass New password when requesting account setup on an already 1472 * authenticated stream 1473 * @return True on success 1474 */ 1475 bool requestRegister(bool data, bool set = true, 1476 const String& newPass = String::empty()); 1477 1478 protected: 1479 /** 1480 * Process elements in Running state 1481 * @param xml Received element (will be consumed) 1482 * @param from Already parsed source JID 1483 * @param to Already parsed destination JID 1484 * @return False if stream termination was initiated 1485 */ 1486 virtual bool processRunning(XmlElement* xml, const JabberID& from, 1487 const JabberID& to); 1488 1489 /** 1490 * Process stream start elements while waiting for them 1491 * @param xml Received xml element 1492 * @param from The 'from' attribute 1493 * @param to The 'to' attribute 1494 * @return False if stream termination was initiated 1495 */ 1496 virtual bool processStart(const XmlElement* xml, const JabberID& from, 1497 const JabberID& to); 1498 1499 /** 1500 * Process elements in Auth state 1501 * @param xml Received element (will be consumed) 1502 * @param from Already parsed source JID 1503 * @param to Already parsed destination JID 1504 * @return False if stream termination was initiated 1505 */ 1506 virtual bool processAuth(XmlElement* xml, const JabberID& from, 1507 const JabberID& to); 1508 1509 /** 1510 * Process elements in Register state 1511 * @param xml Received element (will be consumed) 1512 * @param from Already parsed source JID 1513 * @param to Already parsed destination JID 1514 * @return False if stream termination was initiated 1515 */ 1516 virtual bool processRegister(XmlElement* xml, const JabberID& from, 1517 const JabberID& to); 1518 1519 /** 1520 * Release memory 1521 */ 1522 virtual void destroyed(); 1523 1524 /** 1525 * Start outgoing stream authentication 1526 * @return True on success 1527 */ 1528 bool startAuth(); 1529 1530 /** 1531 * Start resource binding on outgoing stream 1532 * @return True on success 1533 */ 1534 bool bind(); 1535 1536 private: isRegisterId(XmlElement & xml)1537 inline bool isRegisterId(XmlElement& xml) { 1538 if (!m_registerReq) 1539 return false; 1540 String* id = xml.getAttribute("id"); 1541 return id && id->length() == 1 && (*id)[0] == m_registerReq; 1542 } 1543 1544 String m_account; // Stream account 1545 GenObject* m_userData; // User (upper layer) data 1546 String m_password; // The password 1547 String m_newPassword; // New password 1548 char m_registerReq; // Register requested. 1(data) 2(register) 3(remove) 1549 }; 1550 1551 1552 /** 1553 * This class holds a server to server stream 1554 * @short A server to server stream 1555 */ 1556 class YJABBER_API JBServerStream : public JBStream 1557 { 1558 YCLASS(JBServerStream,JBStream) 1559 friend class JBStream; 1560 public: 1561 /** 1562 * Constructor. Build an incoming stream from a socket 1563 * @param engine Engine owning this stream 1564 * @param socket The socket 1565 * @param component True to build an external component stream 1566 */ 1567 JBServerStream(JBEngine* engine, Socket* socket, bool component = false); 1568 1569 /** 1570 * Constructor. Build an outgoing stream 1571 * @param engine Engine owning this stream 1572 * @param local Local party jabber id 1573 * @param remote Remote party jabber id 1574 * @param dbId Optional dialback id (stream id) 1575 * @param dbKey Optional dialback key to verify 1576 * @param dbOnly True if this is a dialback only stream 1577 * @param params Optional stream parameters 1578 */ 1579 JBServerStream(JBEngine* engine, const JabberID& local, const JabberID& remote, 1580 const char* dbId = 0, const char* dbKey = 0, bool dbOnly = false, 1581 const NamedList* params = 0); 1582 1583 /** 1584 * Constructor. Build an outgoing component stream 1585 * @param engine Engine owning this stream 1586 * @param local Local party jabber id 1587 * @param remote Remote party jabber id 1588 * @param name Optional stream name 1589 * @param params Optional stream parameters 1590 */ 1591 JBServerStream(JBEngine* engine, const JabberID& local, const JabberID& remote, 1592 const String* name = 0, const NamedList* params = 0); 1593 1594 /** 1595 * Check if this is an outgoing dialback stream 1596 * @return True if this stream is an outgoing dialback one 1597 */ dialback()1598 inline bool dialback() const 1599 { return outgoing() && flag(DialbackOnly); } 1600 1601 /** 1602 * Retrieve the list of remote domains. 1603 * This method is not thread safe 1604 * @return The list of remote domains 1605 */ remoteDomains()1606 inline const NamedList& remoteDomains() const 1607 { return m_remoteDomains; } 1608 1609 /** 1610 * Check if this stream has an already authenticated remote domain. 1611 * This method is not thread safe 1612 * @param domain Domain to check 1613 * @param auth Check if the domain is authenticated 1614 * @return True if a domain was found 1615 */ 1616 inline bool hasRemoteDomain(const String& domain, bool auth = true) { 1617 NamedString* tmp = m_remoteDomains.getParam(domain); 1618 return tmp && (!auth || tmp->null()); 1619 } 1620 1621 /** 1622 * Take the dialback key from this stream 1623 * @return NamedString pointer or 0 if there is no dialback key held by this stream 1624 */ takeDb()1625 inline NamedString* takeDb() { 1626 Lock lock(this); 1627 NamedString* tmp = m_dbKey; 1628 m_dbKey = 0; 1629 return tmp; 1630 } 1631 1632 /** 1633 * Get a server stream from this one 1634 * @return JBServerStream pointer 1635 */ serverStream()1636 virtual JBServerStream* serverStream() 1637 { return this; } 1638 1639 /** 1640 * Send a dialback verify response 1641 * @param from The 'from' attribute 1642 * @param to The 'to' attribute 1643 * @param id The 'id' attribute 1644 * @param rsp The response as enumeration: set it to NoError if valid, 1645 * NotAuthorized if invalid or any other error to send a db:verify error type 1646 * @return True on success 1647 */ 1648 bool sendDbVerify(const char* from, const char* to, const char* id, 1649 XMPPError::Type rsp = XMPPError::NoError); 1650 1651 /** 1652 * Send a dialback key response. Update the remote domains list. 1653 * Terminate the stream if there are no more remote domains 1654 * @param from The 'from' attribute 1655 * @param to The 'to' attribute 1656 * @param rsp The response as enumeration: set it to NoError if valid, 1657 * NotAuthorized if invalid or any other error to send a db:result error type 1658 * @return True on success 1659 */ 1660 bool sendDbResult(const JabberID& from, const JabberID& to, 1661 XMPPError::Type rsp = XMPPError::NoError); 1662 1663 /** 1664 * Send dialback data (key/verify) 1665 * @return False if stream termination was initiated 1666 */ 1667 bool sendDialback(); 1668 1669 /** 1670 * Start a component stream (reply to received stream start). 1671 * Send handshake if outgoing 1672 * @param local Local domain. Ignored if outgoing 1673 * @param remote Remote domain. Ignored if outgoing 1674 * @return True on success 1675 */ 1676 bool startComp(const String& local = String::empty(), const String& remote = String::empty()); 1677 1678 protected: 1679 /** 1680 * Release memory 1681 */ 1682 virtual void destroyed(); 1683 1684 /** 1685 * Process elements in Running state 1686 * @param xml Received element (will be consumed) 1687 * @param from Already parsed source JID 1688 * @param to Already parsed destination JID 1689 * @return False if stream termination was initiated 1690 */ 1691 virtual bool processRunning(XmlElement* xml, const JabberID& from, 1692 const JabberID& to); 1693 1694 /** 1695 * Build a stream start XML element 1696 * @return XmlElement pointer 1697 */ 1698 virtual XmlElement* buildStreamStart(); 1699 1700 /** 1701 * Process stream start elements while waiting for them 1702 * @param xml Received xml element 1703 * @param from The 'from' attribute 1704 * @param to The 'to' attribute 1705 * @return False if stream termination was initiated 1706 */ 1707 virtual bool processStart(const XmlElement* xml, const JabberID& from, 1708 const JabberID& to); 1709 1710 /** 1711 * Process elements in Auth state 1712 * @param xml Received element (will be consumed) 1713 * @param from Already parsed source JID 1714 * @param to Already parsed destination JID 1715 * @return False if stream termination was initiated 1716 */ 1717 virtual bool processAuth(XmlElement* xml, const JabberID& from, 1718 const JabberID& to); 1719 1720 /** 1721 * Process dialback key (db:result) requests 1722 * @param xml Received element (will be consumed) 1723 * @param from Already parsed source JID 1724 * @param to Already parsed destination JID 1725 * @return False if stream termination was initiated 1726 */ 1727 bool processDbResult(XmlElement* xml, const JabberID& from, const JabberID& to); 1728 1729 /** 1730 * Adjust a dialback response to avoid sending XEP 0220 'error' to a party 1731 * not advertising rfc3920 version=1 (might not support it) 1732 * @param rsp The response to adjust 1733 */ adjustDbRsp(XMPPError::Type & rsp)1734 inline void adjustDbRsp(XMPPError::Type& rsp) { 1735 Lock lock(this); 1736 if (!flag(StreamRemoteVer1) && rsp != XMPPError::NoError) 1737 rsp = XMPPError::NotAuthorized; 1738 } 1739 1740 /** 1741 * Incoming stream remote domains. 1742 * Each element's value will contain the dialback key if not authenticated 1743 */ 1744 NamedList m_remoteDomains; 1745 1746 private: 1747 NamedString* m_dbKey; // Outgoing: initial dialback key to check 1748 String m_password; // Outgoing component: password 1749 }; 1750 1751 1752 /** 1753 * This class holds a cluster stream 1754 * @short A cluster stream 1755 */ 1756 class YJABBER_API JBClusterStream : public JBStream 1757 { 1758 YCLASS(JBClusterStream,JBStream) 1759 friend class JBStream; 1760 public: 1761 /** 1762 * Constructor. Build an incoming stream from a socket 1763 * @param engine Engine owning this stream 1764 * @param socket The socket 1765 */ 1766 JBClusterStream(JBEngine* engine, Socket* socket); 1767 1768 /** 1769 * Constructor. Build an outgoing stream 1770 * @param engine Engine owning this stream 1771 * @param local Local party jabber id 1772 * @param remote Remote party jabber id 1773 * @param params Optional stream parameters 1774 */ 1775 JBClusterStream(JBEngine* engine, const JabberID& local, const JabberID& remote, 1776 const NamedList* params = 0); 1777 1778 /** 1779 * Get a cluster stream from this one 1780 * @return JBClusterStream pointer 1781 */ clusterStream()1782 virtual JBClusterStream* clusterStream() 1783 { return this; } 1784 1785 protected: 1786 /** 1787 * Build a stream start XML element 1788 * @return XmlElement pointer 1789 */ 1790 virtual XmlElement* buildStreamStart(); 1791 1792 /** 1793 * Process stream start elements while waiting for them 1794 * @param xml Received xml element 1795 * @param from The 'from' attribute 1796 * @param to The 'to' attribute 1797 * @return False if stream termination was initiated 1798 */ 1799 virtual bool processStart(const XmlElement* xml, const JabberID& from, 1800 const JabberID& to); 1801 1802 /** 1803 * Process elements in Running state 1804 * @param xml Received element (will be consumed) 1805 * @param from Already parsed source JID 1806 * @param to Already parsed destination JID 1807 * @return False if stream termination was initiated 1808 */ 1809 virtual bool processRunning(XmlElement* xml, const JabberID& from, 1810 const JabberID& to); 1811 }; 1812 1813 1814 /** 1815 * This class holds data related to a remote domain. 1816 * The String holds the domain 1817 * @short Options and connect settings for a remote domain 1818 */ 1819 class YJABBER_API JBRemoteDomainDef : public String 1820 { YCLASS(JBRemoteDomainDef,String)1821 YCLASS(JBRemoteDomainDef,String) 1822 public: 1823 /** 1824 * Constructor 1825 * @param domain Domain name 1826 */ 1827 inline JBRemoteDomainDef(const char* domain = 0) 1828 : String(domain), m_port(0), m_flags(0) 1829 {} 1830 1831 /** 1832 * Remote address used to connect to 1833 */ 1834 String m_address; 1835 1836 /** 1837 * Remote port used to connect to 1838 */ 1839 int m_port; 1840 1841 /** 1842 * Domain flags 1843 */ 1844 int m_flags; 1845 }; 1846 1847 1848 /** 1849 * This class holds data used to connect an outgoing stream 1850 * A descendant class should implement the thread run method 1851 * @short A socket connector 1852 */ 1853 class YJABBER_API JBConnect : public GenObject 1854 { 1855 YCLASS(JBConnect,GenObject) 1856 public: 1857 enum Status { 1858 Start = 0, 1859 Address, // Use configured address 1860 Srv, // Use SRV records 1861 Domain // Use stream remote domain 1862 }; 1863 1864 /** 1865 * Constructor. Add itself to the stream's engine 1866 * @param stream The stream to connect 1867 */ 1868 JBConnect(const JBStream& stream); 1869 1870 /** 1871 * Destructor. Remove from engine if still there 1872 */ 1873 virtual ~JBConnect(); 1874 1875 /** 1876 * Stop the thread. This method should be re-implemented 1877 */ 1878 virtual void stopConnect(); 1879 1880 /** 1881 * Retrieve the stream name 1882 * @return Stream name 1883 */ 1884 virtual const String& toString() const; 1885 1886 /** 1887 * Status name dictionary 1888 */ 1889 static const TokenDict s_statusName[]; 1890 1891 protected: 1892 /** 1893 * Connect the socket. 1894 * Retrieve ip/port from engine ant use them if valid or try to use SRV records returned by 1895 * the given domain or use the domain's ip address and the default port given by the stream type. 1896 * Notify the stream on termination. 1897 * This method should be called from it's own thread 1898 */ 1899 void connect(); 1900 1901 private: 1902 // No default constructor JBConnect()1903 inline JBConnect() 1904 {} 1905 // Check if exiting. Release socket if exiting 1906 bool exiting(Socket*& sock); 1907 // Create and try to connect a socket. Return it on success 1908 // Set stop on fatal failure and return 0 1909 Socket* connect(const char* addr, int port, bool& stop); 1910 // Notify termination, remove from engine 1911 void terminated(Socket* sock, bool final); 1912 // Notify connecting to the stream. Return false if stream vanished 1913 bool notifyConnecting(bool sync, bool useCurrentStat = false); 1914 // Delete a socket and zero the pointer 1915 void deleteSocket(Socket*& sock); 1916 // Advance connect status 1917 void advanceStatus(); 1918 1919 int m_status; // Current status 1920 String m_domain; // Remote domain 1921 String m_address; // Remote ip address 1922 int m_port; // Port to connect to 1923 JBEngine* m_engine; // The engine owning this connector 1924 String m_stream; // Stream name 1925 JBStream::Type m_streamType; // Stream type 1926 String m_localIp; // Local ip to bind when connecting 1927 ObjList m_srvs; // SRV records list 1928 }; 1929 1930 1931 /** 1932 * This class holds a Jabber engine 1933 * @short A Jabber engine 1934 */ 1935 class YJABBER_API JBEngine : public DebugEnabler, public Mutex, public GenObject 1936 { 1937 YCLASS(JBEngine,GenObject) 1938 friend class JBStream; 1939 friend class JBConnect; 1940 friend class JBStreamSetProcessor; 1941 public: 1942 /** 1943 * Constructor 1944 * @param name Engine name 1945 */ 1946 JBEngine(const char* name = "jbengine"); 1947 1948 /** 1949 * Destructor 1950 */ 1951 virtual ~JBEngine(); 1952 1953 /** 1954 * Retrieve the stream read buffer length 1955 * @return Stream read buffer length 1956 */ streamReadBuffer()1957 inline unsigned int streamReadBuffer() const 1958 { return m_streamReadBuffer; } 1959 1960 /** 1961 * Check if this engine is exiting 1962 * @return True if this engine is exiting 1963 */ exiting()1964 inline bool exiting() const 1965 { return m_exiting; } 1966 1967 /** 1968 * Set the exiting flag. Terminate all streams 1969 */ setExiting()1970 inline void setExiting() { 1971 if (m_exiting) 1972 return; 1973 m_exiting = true; 1974 dropAll(JBStream::TypeCount,JabberID::empty(),JabberID::empty(), 1975 XMPPError::Shutdown); 1976 } 1977 1978 /** 1979 * Retrieve maximum redirect counter for outgoing streams 1980 * @return Maximum redirect counter for outgoing streams 1981 */ redirectMax()1982 inline unsigned int redirectMax() const 1983 { return m_redirectMax; } 1984 1985 /** 1986 * Check if TLS is available for outgoing streams 1987 * @return True if TLS is available for outgoing streams 1988 */ hasClientTls()1989 inline bool hasClientTls() const 1990 { return m_hasClientTls; } 1991 1992 /** 1993 * Find a remote domain definition. Return the default settings if not found. 1994 * This method is not thread safe 1995 * @param domain The domain to find 1996 * @return Valid JBRemoteDomainDef pointer 1997 */ remoteDomainDef(const String & domain)1998 inline JBRemoteDomainDef* remoteDomainDef(const String& domain) { 1999 ObjList* o = m_remoteDomains.find(domain); 2000 return o ? static_cast<JBRemoteDomainDef*>(o->get()) : &m_remoteDomain; 2001 } 2002 2003 /** 2004 * Cleanup streams. Stop all threads owned by this engine. Release memory 2005 */ 2006 virtual void destruct(); 2007 2008 /** 2009 * Initialize the engine's parameters. Start private streams if requested 2010 * @param params Engine's parameters 2011 */ 2012 virtual void initialize(const NamedList& params); 2013 2014 /** 2015 * Stop connect threads. Drop all streams. Stop all stream sets. Release memory if final 2016 * @param final True if called from destructor 2017 * @param waitTerminate True to wait for all streams to terminate 2018 */ 2019 virtual void cleanup(bool final = false, bool waitTerminate = true); 2020 2021 /** 2022 * Accept an incoming stream connection. Build a stream. 2023 * Don't delete the socket if false is returned 2024 * @param sock Accepted socket 2025 * @param remote Remote ip and port 2026 * @param t Expected stream type 2027 * @param ssl True if the socket is already using SSL/TLS 2028 * @return True on success 2029 */ 2030 bool acceptConn(Socket* sock, SocketAddr& remote, JBStream::Type t, bool ssl = false); 2031 2032 /** 2033 * Find a stream by its name. This method is thread safe 2034 * @param id The internal id of the stream to find 2035 * @param hint Optional stream type hint 2036 * @return Referenced JBStream pointer or 0 2037 */ 2038 virtual JBStream* findStream(const String& id, 2039 JBStream::Type hint = JBStream::TypeCount); 2040 2041 /** 2042 * Find all c2s streams whose local or remote bare jid matches a given one. 2043 * Ignore destroying streams. 2044 * This method is thread safe 2045 * @param in True for incoming, false for outgoing 2046 * @param jid JID to compare (the local one for outgoing, remote jid for incoming) 2047 * @param flags Optional stream flag to match 2048 * @return List of referenced JBClientStream pointers or 0 2049 */ 2050 ObjList* findClientStreams(bool in, const JabberID& jid, int flags = 0xffffffff); 2051 2052 /** 2053 * Find all c2s streams whose local or remote bare jid matches a given one and 2054 * their resource is found in the given list. 2055 * Ignore destroying streams. 2056 * This method is thread safe 2057 * @param in True for incoming, false for outgoing 2058 * @param jid JID to compare (the local one for outgoing, remote jid for incoming) 2059 * @param resources The list of resources to match 2060 * @param flags Optional stream flag to match 2061 * @return List of referenced JBClientStream pointers or 0 2062 */ 2063 ObjList* findClientStreams(bool in, const JabberID& jid, const ObjList& resources, 2064 int flags = 0xffffffff); 2065 2066 /** 2067 * Find a c2s stream by its local or remote jid. 2068 * This method is thread safe 2069 * @param in True for incoming, false for outgoing 2070 * @param jid JID to compare (the local one for outgoing, remote jid for incoming) 2071 * @return Referenced JBClientStream pointer or 0 2072 */ 2073 JBClientStream* findClientStream(bool in, const JabberID& jid); 2074 2075 /** 2076 * Terminate all streams matching type and/or local/remote jid 2077 * @param type Stream type. Match all stream types if unknown 2078 * @param local Optional local jid to match 2079 * @param remote Optional remote jid to match 2080 * @param error Optional error to be sent to the client 2081 * @param reason Optional error text to be sent to the client 2082 * @return The number of stream terminated 2083 */ 2084 virtual unsigned int dropAll(JBStream::Type type = JBStream::TypeCount, 2085 const JabberID& local = JabberID::empty(), 2086 const JabberID& remote = JabberID::empty(), 2087 XMPPError::Type error = XMPPError::NoError, const char* reason = 0); 2088 2089 /** 2090 * Build an internal stream name 2091 * @param name Destination buffer 2092 * @param stream Stream requesting it 2093 */ buildStreamName(String & name,const JBStream * stream)2094 virtual void buildStreamName(String& name, const JBStream* stream) 2095 {} 2096 2097 /** 2098 * Check if a domain is serviced by this engine 2099 * @param domain Domain to check 2100 * @return True if the given domain is serviced by this engine 2101 */ hasDomain(const String & domain)2102 virtual bool hasDomain(const String& domain) 2103 { return false; } 2104 2105 /** 2106 * Process an event. The default implementation will return the event 2107 * to this engine 2108 * @param ev The event to process 2109 */ 2110 virtual void processEvent(JBEvent* ev); 2111 2112 /** 2113 * Return an event to this engine. The default implementation will send an 2114 * error if apropriate and delete the event 2115 * @param ev The event to return 2116 * @param error Optional error to be returned to the event's XML sender 2117 * @param reason Optional text to be attached to the error 2118 */ 2119 virtual void returnEvent(JBEvent* ev, XMPPError::Type error = XMPPError::NoError, 2120 const char* reason = 0); 2121 2122 /** 2123 * Start stream TLS 2124 * @param stream The stream to enchrypt 2125 */ 2126 virtual void encryptStream(JBStream* stream); 2127 2128 /** 2129 * Connect an outgoing stream 2130 * @param stream The stream to connect 2131 */ 2132 virtual void connectStream(JBStream* stream); 2133 2134 /** 2135 * Start stream compression 2136 * @param stream The stream to compress 2137 * @param formats Supported formats 2138 */ 2139 virtual void compressStream(JBStream* stream, const String& formats); 2140 2141 /** 2142 * Build a dialback key 2143 * @param id The stream id 2144 * @param local Local domain 2145 * @param remote Remote domain 2146 * @param key The dialback key 2147 */ 2148 virtual void buildDialbackKey(const String& id, const String& local, 2149 const String& remote, String& key); 2150 2151 /** 2152 * Check if an outgoing stream exists with the same id and remote peer 2153 * @param stream The calling stream 2154 * @return True if a duplicate is found 2155 */ 2156 bool checkDupId(JBStream* stream); 2157 2158 /** 2159 * Print XML to output 2160 * @param stream Stream requesting the operation 2161 * @param send True if sending, false if receiving 2162 * @param xml XML to print 2163 */ 2164 virtual void printXml(const JBStream* stream, bool send, XmlChild& xml) const; 2165 2166 /** 2167 * Print an XML fragment to output 2168 * @param stream Stream requesting the operation 2169 * @param send True if sending, false if receiving 2170 * @param frag XML fragment to print 2171 */ 2172 virtual void printXml(const JBStream* stream, bool send, XmlFragment& frag) const; 2173 2174 protected: 2175 /** 2176 * Add a stream to one of the stream lists 2177 * @param stream The stream to add 2178 */ 2179 virtual void addStream(JBStream* stream); 2180 2181 /** 2182 * Remove a stream 2183 * @param stream The stream to remove 2184 * @param delObj True to release the stream, false to remove it from list 2185 * without releasing it 2186 */ 2187 virtual void removeStream(JBStream* stream, bool delObj = true); 2188 2189 /** 2190 * Stop all stream sets 2191 * @param waitTerminate True to wait for all streams to terminate 2192 */ 2193 virtual void stopStreamSets(bool waitTerminate = true) 2194 {} 2195 2196 /** 2197 * Retrieve the list of streams of a given type. 2198 * Descendant must implement it 2199 * @param list The destination list to set 2200 * @param type Stream type 2201 */ getStreamList(RefPointer<JBStreamSetList> & list,int type)2202 virtual void getStreamList(RefPointer<JBStreamSetList>& list, int type) 2203 {} 2204 2205 /** 2206 * Retrieve all streams 2207 * @param list The destination list to set. The first index will be filled with the 2208 * c2s streams list, the second index will be set to the s2s stream list 2209 * @param type Optional stream type 2210 */ 2211 inline void getStreamLists(RefPointer<JBStreamSetList> list[JBStream::TypeCount], 2212 int type = JBStream::TypeCount) { 2213 if (type == JBStream::c2s || type == JBStream::TypeCount) 2214 getStreamList(list[JBStream::c2s],JBStream::c2s); 2215 if (type == JBStream::s2s || type == JBStream::TypeCount) 2216 getStreamList(list[JBStream::s2s],JBStream::s2s); 2217 if (type == JBStream::comp || type == JBStream::TypeCount) 2218 getStreamList(list[JBStream::comp],JBStream::comp); 2219 if (type == JBStream::cluster || type == JBStream::TypeCount) 2220 getStreamList(list[JBStream::cluster],JBStream::cluster); 2221 } 2222 2223 /** 2224 * Find a stream by its name in a given set list 2225 * @param id The name of the stream to find 2226 * @param list The list to search for a stream 2227 * @return Referenced JBStream pointer or 0 2228 */ 2229 JBStream* findStream(const String& id, JBStreamSetList* list); 2230 2231 bool m_exiting; // Engine exiting flag 2232 JBRemoteDomainDef m_remoteDomain; // Default remote domain definition 2233 ObjList m_remoteDomains; // Remote domain definitions 2234 unsigned char m_restartMax; // Maximum value for stream restart counter 2235 unsigned int m_restartUpdInterval; // Update interval for stream restart counter 2236 unsigned int m_setupTimeout; // Overall stream setup timeout 2237 unsigned int m_startTimeout; // Wait stream start period 2238 unsigned int m_connectTimeout; // Outgoing: socket connect timeout 2239 unsigned int m_srvTimeout; // SRV query timeout 2240 unsigned int m_pingInterval; // Stream idle interval (no data received) 2241 unsigned int m_pingTimeout; // Sent ping timeout 2242 unsigned int m_idleTimeout; // Stream idle timeout (nothing sent or received) 2243 unsigned int m_pptTimeoutC2s; // Client streams postpone termination intervals 2244 unsigned int m_pptTimeout; // Non client streams postpone stream termination intervals 2245 unsigned int m_streamReadBuffer; // Stream read buffer length 2246 unsigned int m_maxIncompleteXml; // Maximum length of an incomplete xml 2247 unsigned int m_redirectMax; // Max redirect counter for outgoing streams 2248 bool m_hasClientTls; // True if TLS is available for outgoing streams 2249 int m_printXml; // Print XML data to output 2250 bool m_initialized; // True if already initialized 2251 2252 private: 2253 // Add/remove a connect stream thread when started/stopped 2254 void connectStatus(JBConnect* conn, bool started); 2255 // Stop a connect stream 2256 void stopConnect(const String& name); 2257 2258 ObjList m_connect; // Connecting streams 2259 }; 2260 2261 /** 2262 * This class implements a Jabber server engine 2263 * @short A Jabber server engine 2264 */ 2265 class YJABBER_API JBServerEngine : public JBEngine 2266 { 2267 YCLASS(JBServerEngine,JBEngine) 2268 public: 2269 /** 2270 * Constructor 2271 * @param name Engine name 2272 */ 2273 JBServerEngine(const char* name = "jbserverengine"); 2274 2275 /** 2276 * Destructor 2277 */ 2278 ~JBServerEngine(); 2279 2280 /** 2281 * Terminate all streams. Stop all sets processors. Release memory if final 2282 * @param final True if called from destructor 2283 * @param waitTerminate True to wait for all streams to terminate 2284 */ 2285 virtual void cleanup(bool final = false, bool waitTerminate = true); 2286 2287 /** 2288 * Build an internal stream name 2289 * @param name Destination buffer 2290 * @param stream Stream requesting it 2291 */ buildStreamName(String & name,const JBStream * stream)2292 virtual void buildStreamName(String& name, const JBStream* stream) 2293 { name << "stream/" << getStreamIndex(); } 2294 2295 /** 2296 * Find a server to server or component stream by local/remote domain. 2297 * Skip over outgoing dialback only streams 2298 * This method is thread safe 2299 * @param local Local domain 2300 * @param remote Remote domain 2301 * @param out True to find an outgoing stream, false to find an incoming one. 2302 * Ignored for component streams 2303 * @param auth Check if the remote domain of an incoming s2s stream is authenticated 2304 * @return Referenced JBServerStream pointer or 0 2305 */ 2306 JBServerStream* findServerStream(const String& local, const String& remote, bool out, 2307 bool auth = true); 2308 2309 /** 2310 * Create an outgoing s2s stream. 2311 * @param local Local party domain 2312 * @param remote Remote party domain 2313 * @param dbId Optional dialback id (stream id) 2314 * @param dbKey Optional dialback key to verify 2315 * @param dbOnly True if this is a dialback only stream 2316 * @param params Optional stream parameters 2317 * @return Referenced JBServerStream pointer or 0 if a stream already exists 2318 */ 2319 JBServerStream* createServerStream(const String& local, const String& remote, 2320 const char* dbId = 0, const char* dbKey = 0, bool dbOnly = false, 2321 const NamedList* params = 0); 2322 2323 /** 2324 * Create an outgoing comp stream. 2325 * @param name Stream name 2326 * @param local Local party domain 2327 * @param remote Remote party domain 2328 * @param params Optional stream parameters 2329 * @return Referenced JBServerStream pointer or 0 if a stream already exists 2330 */ 2331 JBServerStream* createCompStream(const String& name, const String& local, const String& remote, 2332 const NamedList* params = 0); 2333 2334 /** 2335 * Find a cluster stream by remote domain. 2336 * This method is thread safe 2337 * @param remote Remote jid 2338 * @param skip Optional stream to skip 2339 * @return Referenced JBClusterStream pointer or 0 2340 */ 2341 JBClusterStream* findClusterStream(const String& remote, JBClusterStream* skip = 0); 2342 2343 /** 2344 * Create an outgoing cluster stream. 2345 * This method is thread safe 2346 * @param local Local party domain 2347 * @param remote Remote party domain 2348 * @param params Optional stream parameters 2349 * @return Referenced JBClusterStream pointer or 0 if a stream already exists 2350 */ 2351 virtual JBClusterStream* createClusterStream(const String& local, 2352 const String& remote, const NamedList* params = 0); 2353 2354 /** 2355 * Terminate all incoming c2s streams matching a given JID 2356 * This method is thread safe 2357 * @param jid Client JID 2358 * @param error Optional error to be sent to the client 2359 * @param reason Optional error text to be sent to the client 2360 * @return The number of stream terminated 2361 */ 2362 unsigned int terminateClientStreams(const JabberID& jid, 2363 XMPPError::Type error = XMPPError::NoError, const char* reason = 0); 2364 2365 protected: 2366 /** 2367 * Add a stream to one of the stream lists 2368 * @param stream The stream to add 2369 */ 2370 virtual void addStream(JBStream* stream); 2371 2372 /** 2373 * Remove a stream 2374 * @param stream The stream to remove 2375 * @param delObj True to release the stream, false to remove it from list 2376 * without releasing it 2377 */ 2378 virtual void removeStream(JBStream* stream, bool delObj = true); 2379 2380 /** 2381 * Stop all stream sets 2382 * @param waitTerminate True to wait for all streams to terminate 2383 */ 2384 virtual void stopStreamSets(bool waitTerminate = true); 2385 2386 /** 2387 * Retrieve the list of streams of a given type 2388 * @param list The destination list to set 2389 * @param type Stream type 2390 */ 2391 virtual void getStreamList(RefPointer<JBStreamSetList>& list, int type); 2392 2393 /** 2394 * Retrieve the stream lists of a given type 2395 * @param type Stream type 2396 * @param recv Receive stream list to set 2397 * @param process Process stream list to set 2398 */ 2399 virtual void getStreamListsType(int type, RefPointer<JBStreamSetList>& recv, 2400 RefPointer<JBStreamSetList>& process); 2401 2402 /** 2403 * Increment and return the stream index counter 2404 * @return Current stream index 2405 */ getStreamIndex()2406 inline unsigned int getStreamIndex() { 2407 Lock lock(this); 2408 return ++m_streamIndex; 2409 } 2410 2411 unsigned int m_streamIndex; // Index used to build stream name 2412 JBStreamSetList* m_c2sReceive; // c2s streams receive list 2413 JBStreamSetList* m_c2sProcess; // c2s streams process list 2414 JBStreamSetList* m_s2sReceive; // s2s streams receive list 2415 JBStreamSetList* m_s2sProcess; // s2s streams process list 2416 JBStreamSetList* m_compReceive; // comp streams receive list 2417 JBStreamSetList* m_compProcess; // comp streams process list 2418 JBStreamSetList* m_clusterReceive; // cluster streams receive list 2419 JBStreamSetList* m_clusterProcess; // cluster streams process list 2420 }; 2421 2422 /** 2423 * This class implements a Jabber client engine 2424 * @short A Jabber client engine 2425 */ 2426 class YJABBER_API JBClientEngine : public JBEngine 2427 { 2428 YCLASS(JBClientEngine,JBEngine) 2429 public: 2430 /** 2431 * Constructor 2432 * @param name Engine name 2433 */ 2434 JBClientEngine(const char* name = "jbclientengine"); 2435 2436 /** 2437 * Destructor 2438 */ 2439 ~JBClientEngine(); 2440 2441 /** 2442 * Terminate all streams. Stop all sets processors. Release memory if final 2443 * @param final True if called from destructor 2444 * @param waitTerminate True to wait for all streams to terminate 2445 */ 2446 virtual void cleanup(bool final = false, bool waitTerminate = true); 2447 2448 /** 2449 * Find a stream by account 2450 * @param account Account name 2451 * @return Referenced JBClientStream pointer or 0 2452 */ 2453 JBClientStream* findAccount(const String& account); 2454 2455 /** 2456 * Build an outgoing client stream 2457 * @param account Account name 2458 * @param params Stream parameters 2459 * @param name Optional stream name 2460 * @return Referenced JBClientStream pointer or 0 if a stream already exists 2461 */ 2462 JBClientStream* create(const String& account, const NamedList& params, 2463 const String& name = String::empty()); 2464 2465 /** 2466 * Retrieve the list of streams of a given type 2467 * @param list The destination list to set 2468 * @param type Stream type 2469 */ 2470 virtual void getStreamList(RefPointer<JBStreamSetList>& list, int type); 2471 2472 protected: 2473 /** 2474 * Add a stream to one of the stream lists 2475 * @param stream The stream to add 2476 */ 2477 virtual void addStream(JBStream* stream); 2478 2479 /** 2480 * Remove a stream 2481 * @param stream The stream to remove 2482 * @param delObj True to release the stream, false to remove it from list 2483 * without releasing it 2484 */ 2485 virtual void removeStream(JBStream* stream, bool delObj = true); 2486 2487 /** 2488 * Stop all stream sets 2489 * @param waitTerminate True to wait for all streams to terminate 2490 */ 2491 virtual void stopStreamSets(bool waitTerminate = true); 2492 2493 JBStreamSetList* m_receive; // Streams receive list 2494 JBStreamSetList* m_process; // Streams process list 2495 }; 2496 2497 /** 2498 * This class holds a set of streams to be processed in an uniform way. 2499 * This is a base class for specialized stream list processors. 2500 * Its process() method should be called in its own thread 2501 * @short A set of streams to be processed in an uniform way 2502 */ 2503 class YJABBER_API JBStreamSet : public GenObject, public Mutex 2504 { 2505 YCLASS(JBStreamSet,GenObject); 2506 friend class JBStreamSetList; 2507 public: 2508 /** 2509 * Destructor. Delete the owned streams. Remove from owner 2510 */ 2511 virtual ~JBStreamSet(); 2512 2513 /** 2514 * Retrieve the list of clients. 2515 * Make sure the set is locked before calling this method 2516 * @return The list of clients 2517 */ clients()2518 inline ObjList& clients() 2519 { return m_clients; } 2520 2521 /** 2522 * Add a stream to the set. The stream's reference counter will be increased. 2523 * This method doesn't check if the stream is already added 2524 * @param client The stream to append 2525 * @return True on success, false if there is no more room in this set 2526 */ 2527 virtual bool add(JBStream* client); 2528 2529 /** 2530 * Remove a stream from set 2531 * @param client The stream to remove 2532 * @param delObj True to release the stream, false to remove it from list 2533 * without releasing it 2534 * @return True on success, false if not found 2535 */ 2536 virtual bool remove(JBStream* client, bool delObj = true); 2537 2538 /** 2539 * Terminate all streams matching local/remote jid 2540 * @param local Optional local jid to match 2541 * @param remote Optional remote jid to match 2542 * @param error Optional error to be sent to the client 2543 * @param reason Optional error text to be sent to the client 2544 * @return The number of streams terminated 2545 */ 2546 unsigned int dropAll(const JabberID& local = JabberID::empty(), 2547 const JabberID& remote = JabberID::empty(), 2548 XMPPError::Type error = XMPPError::NoError, const char* reason = 0); 2549 2550 /** 2551 * Process the list. 2552 * Returns as soon as there are no more streams in the list 2553 */ 2554 void run(); 2555 2556 /** 2557 * Start running 2558 * @return True on success 2559 */ 2560 virtual bool start(); 2561 2562 /** 2563 * Stop running 2564 */ 2565 virtual void stop(); 2566 2567 protected: 2568 /** 2569 * Constructor 2570 * @param owner The list owning this set 2571 */ 2572 JBStreamSet(JBStreamSetList* owner); 2573 2574 /** 2575 * This method is called from run() with the list unlocked and stream's 2576 * reference counter increased. 2577 * A specialized processor must implement this method 2578 * @param stream The stream to process 2579 * @return True if something was processed 2580 */ 2581 virtual bool process(JBStream& stream) = 0; 2582 2583 bool m_changed; // List changed flag 2584 bool m_exiting; // The thread is exiting (don't accept clients) 2585 JBStreamSetList* m_owner; // The list owning this set 2586 ObjList m_clients; // The streams list 2587 2588 private: JBStreamSet()2589 JBStreamSet() {} // Private default constructor (forbidden) 2590 }; 2591 2592 2593 /** 2594 * This class holds a set specialized in stream processing 2595 * @short Specialized stream processor 2596 */ 2597 class YJABBER_API JBStreamSetProcessor : public JBStreamSet 2598 { 2599 YCLASS(JBStreamSetProcessor,JBStreamSet); 2600 protected: 2601 /** 2602 * Constructor 2603 * @param owner The list owning this set 2604 */ JBStreamSetProcessor(JBStreamSetList * owner)2605 inline JBStreamSetProcessor(JBStreamSetList* owner) 2606 : JBStreamSet(owner) 2607 {} 2608 2609 /** 2610 * This method is called from run() with the list unlocked and stream's 2611 * reference counter increased. 2612 * Calls stream's getEvent(). Pass a generated event to the engine 2613 * Remove the stream from its engine on destroy 2614 * @param stream The stream to process 2615 * @return True if an event was generated by the stream 2616 */ 2617 virtual bool process(JBStream& stream); 2618 }; 2619 2620 2621 /** 2622 * This class holds a set specialized in stream data receiver 2623 * @short Specialized stream data receiver 2624 */ 2625 class YJABBER_API JBStreamSetReceive : public JBStreamSet 2626 { 2627 YCLASS(JBStreamSetReceive,JBStreamSet); 2628 protected: 2629 /** 2630 * Constructor. Build the read buffer 2631 * @param owner The list owning this set 2632 */ 2633 JBStreamSetReceive(JBStreamSetList* owner); 2634 2635 /** 2636 * This method is called from run() with the list unlocked and stream's 2637 * reference counter increased. 2638 * Calls stream's readSocket() 2639 * @param stream The stream to process 2640 * @return True if the stream received any data 2641 */ 2642 virtual bool process(JBStream& stream); 2643 2644 protected: 2645 DataBlock m_buffer; // Read buffer 2646 }; 2647 2648 2649 /** 2650 * This class holds a list of stream sets. 2651 * The purpose is to create a list of threads 2652 * @short A list of stream sets 2653 */ 2654 class YJABBER_API JBStreamSetList : public RefObject, public Mutex 2655 { 2656 YCLASS(JBStreamSetList,RefObject); 2657 friend class JBStreamSet; 2658 public: 2659 /** 2660 * Constructor 2661 * @param engine Engine owning this list 2662 * @param max Maximum streams per set (0 for maximum possible) 2663 * @param sleepMs Time to sleep when idle 2664 * @param name List name (for debugging purposes) 2665 */ 2666 JBStreamSetList(JBEngine* engine, unsigned int max, unsigned int sleepMs, 2667 const char* name); 2668 2669 /** 2670 * Retrieve the stream set list. 2671 * Make sure the list is locked before calling this method 2672 * @return The stream set list 2673 */ sets()2674 inline ObjList& sets() 2675 { return m_sets; } 2676 2677 /** 2678 * Destructor 2679 */ 2680 virtual ~JBStreamSetList(); 2681 2682 /** 2683 * Retrieve the maximum number of streams per set 2684 * @return The maximum number of streams per set 2685 */ maxStreams()2686 inline unsigned int maxStreams() const 2687 { return m_max; } 2688 2689 /** 2690 * Retrieve the number of streams in all sets 2691 * @return The number of streams in all sets 2692 */ streamCount()2693 inline unsigned int streamCount() const 2694 { return m_streamCount; } 2695 2696 /** 2697 * Retrieve the engine owning this list 2698 * @return The engine owning this list 2699 */ engine()2700 inline JBEngine* engine() const 2701 { return m_engine; } 2702 2703 /** 2704 * Add a stream to the list. Build a new set if there is no room in existing sets 2705 * @param client The stream to add 2706 * @return True on success 2707 */ 2708 bool add(JBStream* client); 2709 2710 /** 2711 * Remove a stream from list 2712 * @param client The stream to remove 2713 * @param delObj True to release the stream, false to remove it from list 2714 * without releasing it 2715 */ 2716 void remove(JBStream* client, bool delObj = true); 2717 2718 /** 2719 * Stop one set or all sets 2720 * @param set The set to stop, 0 to stop all 2721 * @param waitTerminate True to wait for all streams to terminate 2722 */ 2723 void stop(JBStreamSet* set = 0, bool waitTerminate = true); 2724 2725 /** 2726 * Get the string representation of this list 2727 * @return The list name 2728 */ 2729 virtual const String& toString() const; 2730 2731 protected: 2732 /** 2733 * Stop all sets. Release memory 2734 */ 2735 virtual void destroyed(); 2736 2737 /** 2738 * Remove a set from list without deleting it 2739 * @param set The set to remove 2740 */ 2741 void remove(JBStreamSet* set); 2742 2743 /** 2744 * Build a specialized stream set. Descendants must override this method 2745 * @return JBStreamSet pointer or 0 2746 */ 2747 virtual JBStreamSet* build(); 2748 2749 JBEngine* m_engine; // The engine owning this list 2750 String m_name; // List name 2751 unsigned int m_max; // The maximum number of streams per set 2752 unsigned int m_sleepMs; // Time to sleep if nothig processed 2753 ObjList m_sets; // The sets list 2754 2755 private: JBStreamSetList()2756 JBStreamSetList() {} // Private default constructor (forbidden) 2757 2758 unsigned int m_streamCount; // Current number of streams in this list 2759 }; 2760 2761 2762 /** 2763 * This class holds entity capability data 2764 * Implements XEP 0115 support 2765 * @short Entity capability 2766 */ 2767 class YJABBER_API JBEntityCaps : public String 2768 { 2769 YCLASS(JBEntityCaps,String); 2770 public: 2771 /** 2772 * Supported XEP 0115 versions 2773 */ 2774 enum { 2775 Ver1_3 = 1, // Version lower then 1.4 (m_data is the node version + advertised extensions) 2776 Ver1_4 = 2, // Version 1.4 or greater (m_data is the SHA-1 hash of features and identities) 2777 }; 2778 2779 /** 2780 * Constructor 2781 * @param id Object id 2782 * @param version Entity caps version 2783 * @param node Entity node 2784 * @param data Entity data 2785 */ JBEntityCaps(const char * id,char version,const char * node,const char * data)2786 inline JBEntityCaps(const char* id, char version, const char* node, const char* data) 2787 : String(id), 2788 m_version(version), m_node(node), m_data(data) 2789 {} 2790 2791 /** 2792 * Check if a given feature is found in the list 2793 * @param ns The feature to check 2794 * @return True if the feature was found in the list 2795 */ hasFeature(int ns)2796 inline bool hasFeature(int ns) 2797 { return 0 != m_features.get(ns); } 2798 2799 /** 2800 * Check if an audio capability is present 2801 * @return True if an audio capability is present 2802 */ hasAudio()2803 inline bool hasAudio() { 2804 return hasFeature(XMPPNamespace::JingleAppsRtpAudio) || 2805 hasFeature(XMPPNamespace::JingleAudio) || 2806 hasFeature(XMPPNamespace::JingleVoiceV1); 2807 } 2808 2809 /** 2810 * Build an entity caps id 2811 * @param buf Destination buffer 2812 * @param version Entity caps version 2813 * @param node Entity node 2814 * @param data Entity data 2815 * @param ext Optional entity extensions 2816 */ 2817 static inline void buildId(String& buf, char version, const char* node, 2818 const char* data, String* ext = 0) 2819 { buf << (int)version << node << data << (ext ? ext->c_str() : ""); } 2820 2821 char m_version; 2822 String m_node; 2823 String m_data; 2824 XMPPFeatureList m_features; 2825 2826 private: JBEntityCaps()2827 JBEntityCaps() {} 2828 }; 2829 2830 2831 /** 2832 * This class holds data and offer entity capability services. 2833 * Implements XEP 0115 support 2834 * @short Entity capability list manager 2835 */ 2836 class YJABBER_API JBEntityCapsList : public ObjList, public Mutex 2837 { 2838 YCLASS(JBEntityCapsList,ObjList); 2839 public: 2840 /** 2841 * Constructor 2842 */ JBEntityCapsList()2843 inline JBEntityCapsList() 2844 : Mutex(true,"JBEntityCapsList"), m_enable(true), m_reqIndex(0) 2845 { m_reqPrefix << "xep0115" << (unsigned int)Time::msecNow() << "_"; } 2846 2847 /** 2848 * Retrieve an entity caps object. This method is not thread safe 2849 * @param id The id to find 2850 * @return JBEntityCaps pointer or 0 2851 */ findCaps(const String & id)2852 inline JBEntityCaps* findCaps(const String& id) { 2853 for (ObjList* o = skipNull(); o; o = o->skipNext()) 2854 if (o->get()->toString() == id) 2855 return static_cast<JBEntityCaps*>(o->get()); 2856 return 0; 2857 } 2858 2859 /** 2860 * Expire pending requests. 2861 * This method is thread safe 2862 * @param msecNow Current time 2863 */ 2864 void expire(u_int64_t msecNow = Time::msecNow()); 2865 2866 /** 2867 * Process a response. 2868 * This method is thread safe 2869 * @param rsp The element to process 2870 * @param id The element's id 2871 * @param ok True if the response is a result one, false if it's an error 2872 * @return True if the element was processed (handled) 2873 */ 2874 bool processRsp(XmlElement* rsp, const String& id, bool ok); 2875 2876 /** 2877 * Request entity capabilities. 2878 * This method is thread safe 2879 * @param stream The stream to send the request 2880 * @param from The 'from' attribute 2881 * @param to The 'to' attribute 2882 * @param id Entity caps id 2883 * @param version Entity caps version 2884 * @param node Entity node 2885 * @param data Entity caps data 2886 */ 2887 void requestCaps(JBStream* stream, const char* from, const char* to, const String& id, 2888 char version, const char* node, const char* data); 2889 2890 /** 2891 * Build an XML document from this list. 2892 * This method is thread safe 2893 * @param rootName Document root element name 2894 * @return XmlDocument pointer 2895 */ 2896 XmlDocument* toDocument(const char* rootName = "entitycaps"); 2897 2898 /** 2899 * Build this list from an XML document. 2900 * This method is thread safe 2901 * @param doc Document to build from 2902 * @param rootName Document root element name (it will be checked if set) 2903 * @return XmlDocument pointer 2904 */ 2905 void fromDocument(XmlDocument& doc, const char* rootName = "entitycaps"); 2906 2907 /** 2908 * Process an element containing an entity capabily child. 2909 * Request capabilities if not found in the list. 2910 * This method is thread safe 2911 * @param capsId String to be filled with entity caps object id 2912 * (empty if an entity caps child is not found in element ) 2913 * @param xml XML element to process 2914 * @param stream The stream used to request capabilities 2915 * @param from The 'from' attribute of the request stanza 2916 * @param to The 'to' attribute of the request stanza 2917 * @return True if processed (already found, added or request sent) 2918 */ 2919 virtual bool processCaps(String& capsId, XmlElement* xml, JBStream* stream, 2920 const char* from, const char* to); 2921 2922 /** 2923 * Add capabilities to a list. 2924 * This method is thread safe 2925 * @param list Destination list 2926 * @param id Entity caps id 2927 */ addCaps(NamedList & list,const String & id)2928 inline void addCaps(NamedList& list, const String& id) { 2929 Lock lock(this); 2930 JBEntityCaps* caps = findCaps(id); 2931 if (caps) 2932 addCaps(list,*caps); 2933 } 2934 2935 /** 2936 * Add capabilities to a list. 2937 * This method is not thread safe 2938 * @param list Destination list 2939 * @param caps Entity caps to add 2940 */ 2941 virtual void addCaps(NamedList& list, JBEntityCaps& caps); 2942 2943 /** 2944 * Load (reset) this list from an XML document file. 2945 * This method is thread safe 2946 * @param file The file to load 2947 * @param enabler The debug enabler used to output messages 2948 * @return True on success 2949 */ 2950 bool loadXmlDoc(const char* file, DebugEnabler* enabler = 0); 2951 2952 /** 2953 * Save this list to an XML document file. 2954 * This method is thread safe 2955 * @param file The file to save 2956 * @param enabler The debug enabler used to output messages 2957 * @return True on success 2958 */ 2959 bool saveXmlDoc(const char* file, DebugEnabler* enabler = 0); 2960 2961 /** 2962 * Check if an XML element has a 'c' entity capability child and decode it 2963 * @param xml The element to process 2964 * @param version Entity caps version 2965 * @param node Entity node attribute 2966 * @param ver Entity ver attribute 2967 * @param ext Entity ext attribute if version is less the 1.4 2968 * @return True if a child was succesfully decoded 2969 */ 2970 static bool decodeCaps(const XmlElement& xml, char& version, String*& node, 2971 String*& ver, String*& ext); 2972 2973 /** 2974 * Enabled flag 2975 */ 2976 bool m_enable; 2977 2978 protected: 2979 /** 2980 * Caps list item add notification for descendants. 2981 * This method is called when processing responses with the list locked 2982 * @param caps Changed caps object. 0 if none specified 2983 */ capsAdded(JBEntityCaps * caps)2984 virtual void capsAdded(JBEntityCaps* caps) 2985 {} 2986 2987 unsigned int m_reqIndex; // Disco info request index 2988 String m_reqPrefix; // Prefix for disco info stanza id 2989 ObjList m_requests; // List of sent disco info requests 2990 }; 2991 2992 }; // namespace TelEngine 2993 2994 #endif /* __YATEJABBER_H */ 2995 2996 /* vi: set ts=8 sw=4 sts=4 noet: */ 2997