|
NAMEJabber::Lite - Standalone library for communicating with Jabber servers.SYNOPSISuse Jabber::Lite; my $jlobj = Jabber::Lite->new(); $jlobj->connect( %args ); $jlobj->authenticate( %args ); my $stillgoing = 1; while( $stillgoing ){ my $tval = $jlobj->process(); if( $tval == 1 ){ my $curobj = $jlobj->get_latest(); # Process based on the object. }elsif( $tval < 0 ){ $stillgoing = 0; } } GOALSJabber::Lite is intended to be a pure perl library for interacting with Jabber servers, and be able to run under any version of perl that has the Sockets library.DESCRIPTIONJabber::Lite is, as the name implies, a small 'lite' library for dealing with Jabber servers, implemented entirely in perl. Whilst it is small, it does try to be fairly complete for common tasks.Whats in the box? Jabber::Lite is able to connect to a Jabber server, read from the socket, and supply XML objects to the application as the application reads them. Its function calls are mostly compatible with Jabber::NodeFactory and Jabber::Connection. Surprisingly, it can also function as a stand-alone XML parser (which was not the author's original intent, but hey, it works). Whats not in the box? Any requirement for a recent perl version, UTF-8 support, as well as a fully XML-compliant Parser. Applications using this library will need to be aware that this library uses a combination of 'pull' and 'push' methods of supplying XML objects. Handlers for given object types can be put in place, however if an object is not fully handled by a Handler, the object will 'block' further objects until the Application retrieves it. Read the notes on ->process() and ->get_latest() for further details. The inbuilt parser, fully implemented in perl, is more properly termed an XML Recogniser. If you want a fully compliant XML Parser, look elsewhere. This one recognises just enough XML for its purposes ;) METHODSThe methods within have been organised into several categories, listed here for your searching pleasure:
METHODS - InitialisationnewReturns a new instance of the object. Takes a hash of arguments which are passed straight to ->init();init(Re-)initialises data stored on the object, removing most references. Used by ->new() to ensure that there is no 'bad' stuff around. Takes a hash of values including:
The various 'max' settings are enforced by ->do_read(). Calling ->parse_more() directly will not incur the dubious protections afforded by this. METHODS - ResolvingBefore connecting, you may need to resolve something in order to find out where to point the connection methods to. Heres some methods for resolving.resolveDeals with the intricacies of figuring out what you need to connect to. Understands SRV records, and how things can resolve differently depending on whether you want a server or client connection. Takes a hash of 'Domain', a 'Timeout' value (in seconds) and a 'Type' of 'client' or 'server'. Returns a boolean success value of 1 (success) or 0 (failure).Note that no DNSSEC or TSIG verification is done. resolvedReturns a list of what the last ->resolve() request actually resolved to. This is an ordered-by-priority, randomised-by-weight @list of 'IP.address,port'. If there is no ',port', then no port information was present in the DNS, and the application's own idea of default port should be used.The ordering is done according to the method set out in RFC2782(DNS SRV Records). Of particular note is page 3, where a randomisation function is applied to the ordering of SRV RRs with equal priority. Thus, each time this function is called, it may return a different ordering of IPs. bgresolveAs per ->resolve(), but submit in the background. This returns 1 if the query could be submitted, and 0 if not. ( Actually, ->resolve() is simply a wrapper around ->bgresolve() and ->bgresolved() )bgresolvedChecks to see whether the last ->bgresolve() request completed. Only one request in the background can be ongoing at a time. Returns -1 if the resolution is still pending, 0 if the resolution failed, and 1 if the resolution was successful. ->resolved() can then be called to retrieve the list.METHODS - ConnectingBefore jabbering at other entities, you need to connect to a remote host.connectConnect to a Jabber server. Only one connection at a time is supported on any given object. Returns 0 if unsuccessful, 1 if successful.Takes a hash of values as follows:
Note for people with their own connection requirements: The ->connect() method is comparitively simple (ha!); just initiating a TCP connection and setting up handlers to negotiate TLS. Those wishing to set up their own connection handlers are welcome to do so, but search this library's code for the string 'grok incomplete' before doing so. Those concerned about the ?xml attributes emitted by the remote end can reference the ->xml_version(), ->xml_encoding() and ->xml_standalone) methods. bgconnectThe ->bgconnect() method is just the same as the ->connect() method, except it returns straight away. Use the ->bgconnected() method to test for an answer to that 4am question, am I connected or not?Returns 1 if the TCP connection could be started, and 0 if not. If this method returns 0, you probably have bigger problems. Note: The ->bgconnect() method just calls ->connect() with the background flag set. bgconnectedThis tests to see whether the current connection has succeeded. It returns -1 if not yet, 0 if failed (and socket has been closed) and 1 if successful. It takes a hash of:RunProcess - Invoke ->process() internally ProcessTime - time to pass to ->process() (default 0 ) If RunProcess is not specified, you will have to invoke ->process() seperately. METHODS - AuthenticatingIt helps if the remote server knows who you are.authenticateAttempt to authenticate to the Jabber server over a connected socket. It takes a hash of:
It returns 1 on success, and 0 on failure. bgauthenticateThis accepts the same arguments as ->authenticate(), but returns after sending the initial packets required to start the authentication steps.Note: This method will block on older servers where ->listauths() has to ask for a packet. bgauthenticatedThis tests to see whether the current authentication steps have succeeded. It returns -1 if not yet, 0 if failed and 1 if successful. It takes a hash of:RunProcess - Invoke ->process() internally ProcessTime - time to pass to ->process() (default 0 ) If RunProcess is not specified, you will have to invoke ->process() seperately. authThis is the Jabber::Connection compatibility call. It takes 1 or 3 arguments, being either the shared password (for use when connecting as a component), or the username, password and resource. It returns 1 if successful, 0 if unsuccessful.AuthSendThis is the Net::XMPP::Protocol/Net::Jabber::Component compatibility call. It takes a hash of 'username', 'password' and 'resource', or "secret" and returns a @list of two values, being a success ('ok')/failure string, and a message. Note that apart from 'ok', the success/failure string may not be the same as returned by the Net::XMPP libraries.METHODS - Dealing with <stream:features>Some incidental things.stream_featuresThis method returns the latest <stream:features> tag received from the server, or undef. It is used internally by the ->bind() and ->session() methods.Note that during the ->connect() and ->authenticate() phases, certain of these features may get 'used', and thus not returned by the server the next time it issues a <stream:features> tag. listauthsThis method lists the authentication methods available either to the library or provided by this Jabber server by way of <stream:features>. An optional hash may be provided, where 'Ask' triggers the asking of the server for authentication information according to the 'jabber:iq:auth' namespace (JEP-0078), with the optional 'Username' being supplied as required.The return value is either an @array or %hash of possible authentication methods and mechanisms depending on the 'Want' option ('array' or 'hash'), arranged as per 'method-mechanism', eg 'sasl-digest-md5' or 'jabber:iq:auth-plain'. This method should be called after ->connect(), obviously. Note: If Ask (or JustAsk) is specified, this method will call ->process(), until it gets the reply it is expecting. If other packets are expected during this time, use ->register_handler() to set up callbacks for them, making sure that any <iq> packets in the 'jabber:iq:auth' namespace (<query> subtag) are not swallowed. sessionStarts a session with the remote server, if required by the <stream:features> packet. Called internally by ->authenticate() if DoSession is set as the default '1'. Takes an optional hash of:
Returns 1 if successful, 0 otherwise. bgsessionedChecks to see if the session establishment has completed, returning -1 on still going, 0 on refused and 1 on success.bindBinds a Resource value to the connection, if required by the <stream:features> packet. Called internally by ->authenticate() if DoBind is set as the default '1'. Takes an optional hash of:
Returns 1 if successful, 0 otherwise. If successful, will update the value used by ->connect_jid(). bgbindBackground version of bind. Takes the same arguments as the ->bind() call.bgbindedTechnically this should be 'bgbound', but for consistency with other 'bg' methods, its named this way. Checks to see if the binding has completed, returning -1 on still going, 0 on refused and 1 on success.METHODS - Handling Packetsclear_handlersThis clears any handlers that have been put on the object. Some applications may wish to do this after the standard ->connect() and ->authenticate() methods have returned successfully, as these use handlers to do their jobs.Alternatively, specifying a 'Class' of 'connect' and 'authenticate' will remove just the handlers created by ->connect() and ->authenticate() respectively. WARNING: The standard ->connect() and ->authenticate() (and/or their bg varients) require their configured handlers to be in place. Do not execute ->clear_handlers() between ->connect() and ->authenticate, lest your application suddenly fail to work. This takes a hash of optional arguments, being 'Type' and 'Class'. The 'Type' is the same as the Type supplied to 'register_handler', and if supplied, will delete all callbacks of that Type. The 'Class' is the same as the optional Class supplied to 'register_handler', and if supplied, will delete all callbacks of that class. register_handlerRecord a packet type and a subroutine to be invoked when the matching packet type is received. Multiple handlers for the same packet type can be registered. Each of these handlers is called in succession with the received packet until one returns the constant "r_HANDLED" .Each handler is invoked with two arguments; the object representing the current packet, and a value received from calls to previous handlers. so-called 'parcel' or 'persistent' data. The return value is either the "r_HANDLED" constant or parcel/persistent data to be handed to the next handler. Note: See notes regarding handlers under ->process(). Note: The ->connect() and ->authenticate() methods use handlers to function. Note: A third argument can be supplied to indicate the 'class' of this handler, for usage with ->clear_handlers(). If not supplied, defaults to 'user'. register_intervalRecords a time interval and a subroutine to be invoked when the appropriate time period has elapsed. Takes a hash of:
The subroutine is invoked with a single argument of the current connection object (in case you want to send something), and the value of the 'Argument' hash if supplied. Note: These are executed as a side-effect of running ->process(). If you do not regularly invoke ->process() (or via ->start()), these timeouts will not be invoked. Executing ->process() from within the handler may cause odd things to happen. register_beatThis is the Jabber::Connection compatibility call, and takes two arguments, a time interval and a subroutine. Invokes ->register_interval() .processFor most applications, this is the function to use. It checks to see if anything is available to be read on the socket, reads it in, and returns a success (or otherwise) value. It takes an optional timeout argument, for how long the ->can_read() call can hang around for (default 0).The values returned, which MUST be checked on each call, are: -2: Invalid XML was read. -1: EOF was reached. 0: No action. Data may or may not have been read. 1: A complete object has been read, and is available for retrieval via get_latest(). 2: A complete object was read, but was eaten by a defined handler. Note that after a complete object has been read, any further calls to ->process() will not create additional objects until the current complete object has been retrieved via ->get_latest(). This does not apply if the object was eaten/accepted by a defined handler. Note: ->process() is a wrapper around ->can_read() and ->do_read(), but it executes handlers as well. ->process() will return after every packet read (imho, a better behaviour than simply reading from the socket until the remote end stops sending us data). sendSends either text or an object down the connected socket. Returns a count of the number of bytes read. Will return '-1' if an error occured and the text was not sent.Note that if you send non-XML data (gibberish or incomplete), thats your problem, not mine. METHODS - So Long, and Thanks for all the <fish/>disconnectDisconnect from the Jabber server by sending the closing tags and then closing the connection. Note that no closing '</presence>' tag is sent, but the closing </stream:stream> tag is sent.abortClose the connection abruptly. If the connection is not to a Jabber server, use abort() instead of disconnect().METHODS - These are a few of my incidental thingssocketReturns (or sets) the socket that this object is using. This is provided to support a parent program designed around its own IO::Select() loop. A previously opened socket/filehandle can be supplied as the argument.Note: The library uses sysread() and send/syswrite() as required. Passing in filehandles that do not support these functions is probably a bad idea. Note: There is some juggling of sockets within the ->connect() method when SSL starts up. Whilst a select() on the original, or parent socket will probably still work, it would probably be safer to not include the socket returned by ->socket() in any select() until the ->connect() and ->authenticate() methods have returned. can_readChecks to see whether there is anything further on the socket. Returns 1 if there is data to be read, 0 otherwise.can_writeChecks to see whether the socket can be written to. Returns 1 if so, 0 otherwise.do_readReads in the latest text from the socket, and submits it to be added to the current XML object. Returns:
Applications MUST check the return value on each call. Takes a hash of optional arguments, the most important being: PendingOnly (default 0) - Only process the pending data, do not attempt to read from the socket. ->do_read() also checks the maxobjectsize, maxobjectdepth and maxnamesize. ->do_read() also checks the likely size of the object as it is being read. If it is larger than the maxobjectsize value passed to ->new/->init, the appropriate behaviour will be taken. Note that if the behaviour chosen is to continue parsing but not save (the default), then an attack consisting of <foo><foo><foo> repeated ad nauseum will still eventually exhaust memory. This is because to properly parse the object, the parser must know at which point the object is at, meaning that the name of each <tag> must be stored. is_eofSees whether the socket is still around, based on the last call to ->do_read(). Returns 1 if the socket is at EOF, 0 if the socket not at EOF.is_authenticatedReturns 1 or 0 whether this connection has been authenticated yet.is_connectedReturns 1 or 0 whether this connection is currently connected.is_encryptedReturns 1 or 0 whether this connection is currently encrypted.connect_jidReturns the JID currently associated with this connection, or undef._connect_starttls handlerThis is a helper function (for ->connect) for the starting up of TLS/SSL via the <starttls> tag._connect_handler handlerThis is a helper function (for ->connect) for the handling of some initial tags.xml_versionThis returns the version supplied by the last <?xml?> tag received, and defaults to '1.0'. Refer to the XML reference at <http://www.w3.org/TR/REC-xml/#sec-prolog-dtd> .xml_encodingThis returns the encoding supplied by the last <?xml?> tag received, and defaults to 'UTF-8' if one was not supplied.xml_standaloneThis returns the standalone value supplied by the last <?xml?> tag received, and defaults to 'unknown' if one was not supplied.METHODS - Object commonThese are for the library as XML parser, creating new objects, reading attributes etc.get_latestReturns the latest complete object or undef. This function is only valid on the parent connection object.WARNING: This is a destructive process; a second call will return undef until another object has been read. copy_latestThis returns a copy of the latest object, whether or not it is actually complete. An optional argument may be supplied, which will be used to replace the current object.WARNING: This may return objects which are incomplete, and may not make too much sense. Supplying an argument which is not of this class may produce odd results. clear_latestThis clears the latest object.newNodeCreates a new Node or tag, and returns the object thus created. Takes two arguments, being a required name for the object, and an optional xmlns value. Returns undef if a name was not supplied.A previously created object can be supplied instead. newNodeFromStrCreates a new Node or tag from a supplied string, and returns the object thus created. Takes a single argument, being the string for the object. Returns undef if a string was not supplied.Note: If there was more than one object in the string, the remaining string is tossed away; you only get one object back. insertTagInserts a tag into the current object. Takes the same arguments as ->newNode, and returns the object created.nameReturns, or sets, the name of the object. Takes an optional argument for the new name.Note: No checking or escaping is done on the supplied name. is_completeReturn 1 or 0 whether the current object is complete.getChildrenReturn an @array of subobjects, or undef.getTagReturn a specific child tag if it exists. Takes the name of the tag, and optionally the xmlns value of the tag (first found wins in the case of duplicates).listAttrsReturn an @array of attributes on the current object.attrReturn or set the contents of an attribute. Takes an attribute name as the first argument, and the optional attribute contents (replacing anything there) as the second argument.xmlnsSets or returns the value of the xmlns attribute.dataReturns or sets the data associated with this object. Take an optional argument supplying the data to replace any existing data. Performs encoding/decoding of common XML escapes.rawdataThe same as ->data(), but without the encodings/decodings used. Make sure anything that you add doesn't include valid XML tag characters, or something else will break.parentReturns the parent object of the current object, or undef.hideRemove references to the current object from the parent object, effectively deleting it. Returns 1 if successful, 0 if no valid parent. If there are any child-objects, removes references to this object from them.hidechildRemove references to a child object. Takes an argument of a child object to delete. Returns 1 if successful, 0 if not.hidetreeThis routine removes references to this object, and to objects below it. In certain versions of perl, this may assist with cleanup.toStrReturns the object in a single string. Takes an optional hash consisting of 'FH', being a filehandle reference to send output to instead (useful if you aren't wanting to copy the object into a local variable), and 'GenClose', which defaults to 1 and ensures that the first tag has the proper '/' character when closing the tag.If set to '0', '<stream>' will be output instead of '<stream/>', a highly important distinction when first connecting to Jabber servers (remember that a Jabber connection is really one long '<stream>' tag ). GetXMLThis is the Net::XMPP::Stanza compatibility call, and simply invokes ->toStr(). Note for Ryan: where is ->GetXML() actually documented?METHODS - Object detailed and other stuff.create_and_parseCreates and returns a new instance of an object. Invoked by ->do_read() and ->parse_more(). Takes as an optional argument some text to parse.Returns the new object (or undef), a success value, and any unprocessed text. Success values can be one of: -2 Invalid XML 0 No errors 1 Complete object parse_moreParses some text and adds it to an existing object. Creates further sub-objects as appropriate. Returns a success value, and any unprocessed text. Success values can be one of:-2 if a parsing error was found. 0 if no obvious bugs were found. 1 if a complete object was found. The parser, such as it is, will sometimes return text to be prepended with any new text. If the calling application does not keep track of the returned text and supply it the next time, the parser's behaviour is undefined. Most applications will be invoking ->parse_more() via ->do_read() or ->process(), so this situation will not come up. This needs An optional second argument can be supplied which, if 1, will inhibit the saving of most text to memory. This is used by do_read to indicate that an excessively-large object is being read. _curstatusReturns the current status of the parser on the current object. Used by the ->connect() method, but may be useful in debugging the parser.encodeWhen passed a string, returns the string with appropriate XML escapes put in place, eg '&' to '&', '<' to '<' etc.decodeWhen passed a string, returns the string with the XML escapes reversed, eg '&' to '&' and so forth.expandEntityWhen passed an '&' escape string, will return the text that it expands to, based on both a set of predefined escapes, and any escapes that may have been _previously_ defined within the document. Will return undef if it cannot expand the string.This function is non-intuitive, as it will replace 'amp' with 'amp', but 'pre-defined-escape' with 'text that was declared in the <!ENTITY> declaration for pre-defined-escape'. Its prime usage is in the storage of hopefully-compliant-XML data into the object, and is used as part of the data verification routines. ConstXMLNSThis helper function keeps several xmlns strings in one place, to make for easier (sic) upgrading. It takes one argument, and returns the result of that argument's lookup._got_Net_DNSHelper function to load Net::DNS into the current namespace._got_Digest_SHA1Helper function to load Digest::SHA1 into the current namespace._got_Digest_MD5Helper function to load Digest::MD5 into the current namespace._got_Authen_SASLHelper function to load Authen::SASL into the current namespace._got_MIME_Base64Helper function to load MIME::Base64 into the current namespace._got_IO_Socket_SSLHelper function to load IO::Socket::SSL into the current namespace.debugDebug is vor finding de bugs!Prints the supplied string, along with some other useful information, to STDERR, if the initial object was created with the debug flag. versionReturns the major version of the library.HISTORYSeptember 2005: During implementation of a Jabber-based project, the author encountered a machine which for political reasons, could not be upgraded to a version of perl which supported a current version of various Jabber libraries. After getting irritated with having to build a completely new standalone perl environment, together with the ~10 meg, no 11, no 12, no 15 (etc), footprint of libraries required to support XML::Parser, the desire for a lightweight Jabber library was born.December 2005: The author, merrily tossing large chunks of data through his Jabber servers, discovered that XML::Parser does not deal with large data sizes in a graceful fashion. January 2006: The author completed a version which would, at least, not barf on most things. January through September 2006: Being busy with other things, the author periodically ran screaming from memory leakage problems similar to XML::Parser.. Finally, a casual mention in one of the oddest places lead the author to a good explanation of how Perl does not deal with circular dependencies. PREREQUISITES / DEPENDENCIESIO::Socket::INET, IO::Select . Thats it. Although, if you want encryption on your connection, SASL support or reasonable garbage collection in various versions of perl, there are soft dependencies on:
BUGSPerl's garbage collection is at times rather dubious. A prime example is when you have double-linked lists, otherwise known as circular references. Since both objects refer to each other (in recording parent <-> child relationships), perl does not clean them up until the end of the program. Whilst this library does do some tricks to get around this in newer versions of perl, involving proxy objects and 'weaken' from Scalar::Util , this library may leak memory in older versions of perl. Invoking ->hidetree() on a retrieved object before it falls out of scope is recommended (the library does this on some internal objects, perhaps obsessively). Note that you may need to create a copy of a object via ->newNodeFromStr()/->toStr() due to this.AUTHORBruce Campbell, Zerlargal VOF, 2005-2010 . See <http://cpan.zerlargal.org/Jabber::Lite>COPYRIGHTCopyright (c) 2005-7 Bruce Campbell. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.BLATANT COPYINGI am primarily a Sysadmin, and like Perl programmers, Sysadmins are lazy by nature. So, bits of this library were copied from other, existing libraries as follows:->encode(), ->decode() and some function names: L<Jabber::NodeFactory>. ->ConstXMLNS(), SASL handling: L<XML::Stream>
Visit the GSP FreeBSD Man Page Interface. |