README

XMPP

GoDoc Chat License Build Status

Buy Me A Coffee Support Me

An XMPP library in Go.

To use it in your project, import it (or any of its other packages) like so:

import mellium.im/xmpp

If you're looking to get started and need some help, see the API docs or look in the examples/ tree for several simple usage examples.

If you'd like to contribute to the project, see CONTRIBUTING.md.

License

The package may be used under the terms of the BSD 2-Clause License a copy of which may be found in the file "LICENSE". Some code in this package has been copied from Go and is used under the terms of Go's modified BSD license, a copy of which can be found in the LICENSE-GO file.

Unless you explicitly state otherwise, any contribution submitted for inclusion in the work by you shall be licensed as above, without any additional terms or conditions.

Documentation

Overview

Package xmpp provides functionality from the Extensible Messaging and Presence Protocol, sometimes known as "Jabber".

This module is subdivided into several packages. This package provides functionality for establishing an XMPP session, feature negotiation (including an API for defining your own stream features), and handling events. Other important packages include the jid package, which provides an implementation of the XMPP address format, the mux package which provides an XMPP handler that can multiplex payloads to other handlers and functionality for creating your own multiplexers, and the stanza package which provides functionality for transmitting XMPP primitives and errors.

Session Negotiation

There are 9 functions for establishing an XMPP session. Their names are matched by the regular expression:

(New|Receive|Dial)(Client|Server)?Session

If "Dial" is present it means the function uses sane defaults to dial a TCP connection before negotiating an XMPP session on it. Most users will want to call DialClientSession or DialServerSession to create a client-to-server (c2s) or server-to-server (s2s) connection respectively. These methods are the most convenient way to quickly start a connection.

session, err := xmpp.DialClientSession(
    context.TODO(),
    jid.MustParse("me@example.net"),
    xmpp.StartTLS(&tls.Config{…}),
    xmpp.SASL("", pass, sasl.ScramSha1Plus, sasl.ScramSha1, sasl.Plain),
    xmpp.BindResource(),
)

If control over DNS or HTTP-based service discovery is desired, the user can use the dial package to create a connection and then use one of the other session negotiation functions for full control over session initialization.

If "New" or "Dial" is present in the function name it indicates that the session is from the initiating entities perspective while "Receive" indicates the receiving entity. If "Client" or "Server" are present they indicate a C2S or S2S connection respectively, otherwise the function takes a Negotiator and an initial session state to determine the type of session to create.

This also lets the user create the XMPP session over something other than a TCP socket; for example a Unix domain socket or an in-memory pipe. It even allows the use of a different session negotiation protocol altogether such as the WebSocket subprotocol from the websocket package, or the Jabber Component Protocol from the component package.

conn, err := dial.Client(context.TODO(), "tcp", addr)
…
session, err := xmpp.NewSession(
    context.TODO(), addr.Domain(), addr, conn, xmpp.Secure,
    xmpp.NewNegotiator(xmpp.StreamConfig{
        Lang: "en",
        …
    }),
)

The default Negotiator and related functions use a list of StreamFeature's to negotiate the state of the session. Implementations of the most commonly used features (StartTLS, SASL-based authentication, and resource binding) are provided. Custom stream features may be created using the StreamFeature struct. StreamFeatures defined in this module are safe for concurrent use by multiple goroutines and may be created once and then re-used.

Handling Stanzas

Unlike HTTP, the XMPP protocol is asynchronous, meaning that both clients and servers can accept and send requests at any time and responses are not required or may be received out of order. This is accomplished with two XML streams: an input stream and an output stream. To receive XML on the input stream, Session implements the xml.TokenReader interface defined in encoding/xml; this allows session to be wrapped with xml.NewTokenDecoder. To send XML on the output stream, Session has a TokenEncoder method that returns a token encoder that holds a lock on the output stream until it is closed. The session may also buffer writes and has a Flush method which will write any buffered XML to the underlying connection.

Writing individual XML tokens can be tedious and error prone. The stanza package contains functions and structs that aid in the construction of message, presence and info/query (IQ) elements which have special semantics in XMPP and are known as "stanzas". There are 8 methods on Session used for transmitting stanzas and other events over the output stream. Their names are matched by the regular expression:

(Send|Encode)(IQ)?(Element)?

If "Send" is present it means that the method copies one XML token stream into the output stream, while "Encode" indicates that it takes a value and marshals it into XML. If "IQ" is present it means that the stream or value contains an XMPP IQ and the method blocks waiting on a response. If "Element" is present it indicates that the stream or struct is a payload and not the full element to be transmitted and that it should be wrapped in the provided start element token or stanza.

// Send initial presence to let the server know we want to receive messages.
_, err = session.Send(context.TODO(), stanza.WrapPresence(jid.JID{}, stanza.AvailablePresence, nil))

For SendIQ and related methods to correctly handle IQ responses, and to make the common case of polling for incoming XML on the input stream—and possibly writing to the output stream in response—easier, we need a long running goroutine. Session includes the Serve method for starting this processing.

Serve provides a Handler with access to the stream but prevents it from advancing the stream beyond the current element and always advances the stream to the end of the element when the handler returns (even if the handler did not consume the entire element).

err := session.Serve(xmpp.HandlerFunc(func(t xmlstream.TokenReadEncoder, start *xml.StartElement) error {
    d := xml.NewTokenDecoder(t)

    // Ignore anything that's not a message.
    if start.Name.Local != "message" {
        return nil
    }

    msg := struct {
        stanza.Message
        Body string `xml:"body"`
    }{}
    err := d.DecodeElement(&msg, start)
    …
    if msg.Body != "" {
        log.Println("Got message: %q", msg.Body)
    }
}))

It isn't always practical to put all of your logic for handling elements into a single function or method, so the mux package contains an XML multiplexer that can be used to match incoming payloads against a pattern and delegate them to individual handlers. Packages that implement extensions to the core XMPP protocol will often provide handlers that are compatible with types defined in the mux package, and options for registering them with the multiplexer.

Be Advised

This API is unstable and subject to change.

Example (Echobot)
package main

import (
	"context"
	"crypto/tls"
	"encoding/xml"
	"io"
	"log"

	"mellium.im/sasl"
	"mellium.im/xmlstream"
	"mellium.im/xmpp"
	"mellium.im/xmpp/jid"
	"mellium.im/xmpp/stanza"
)

const (
	login = "echo@example.net"
	pass  = "just an example don't hardcode passwords"
)

// MessageBody is a message stanza that contains a body. It is normally used for
// chat messages.
type MessageBody struct {
	stanza.Message
	Body string `xml:"body"`
}

func main() {
	j := jid.MustParse(login)
	s, err := xmpp.DialClientSession(
		context.TODO(), j,
		xmpp.BindResource(),
		xmpp.StartTLS(&tls.Config{
			ServerName: j.Domain().String(),
		}),
		xmpp.SASL("", pass, sasl.ScramSha1Plus, sasl.ScramSha1, sasl.Plain),
	)
	if err != nil {
		log.Printf("Error establishing a session: %q", err)
		return
	}
	defer func() {
		log.Println("Closing session…")
		if err := s.Close(); err != nil {
			log.Printf("Error closing session: %q", err)
		}
		log.Println("Closing conn…")
		if err := s.Conn().Close(); err != nil {
			log.Printf("Error closing connection: %q", err)
		}
	}()

	// Send initial presence to let the server know we want to receive messages.
	err = s.Send(context.TODO(), stanza.Presence{Type: stanza.AvailablePresence}.Wrap(nil))
	if err != nil {
		log.Printf("Error sending initial presence: %q", err)
		return
	}

	s.Serve(xmpp.HandlerFunc(func(t xmlstream.TokenReadEncoder, start *xml.StartElement) error {
		d := xml.NewTokenDecoder(t)

		// Ignore anything that's not a message. In a real system we'd want to at
		// least respond to IQs.
		if start.Name.Local != "message" {
			return nil
		}

		msg := MessageBody{}
		err = d.DecodeElement(&msg, start)
		if err != nil && err != io.EOF {
			log.Printf("Error decoding message: %q", err)
			return nil
		}

		// Don't reflect messages unless they are chat messages and actually have a
		// body.
		// In a real world situation we'd probably want to respond to IQs, at least.
		if msg.Body == "" || msg.Type != stanza.ChatMessage {
			return nil
		}

		reply := MessageBody{
			Message: stanza.Message{
				To: msg.From.Bare(),
			},
			Body: msg.Body,
		}
		log.Printf("Replying to message %q from %s with body %q", msg.ID, reply.To, reply.Body)
		err = t.Encode(reply)
		if err != nil {
			log.Printf("Error responding to message %q: %q", msg.ID, err)
		}
		return nil
	}))
}
Output:

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrInputStreamClosed  = errors.New("xmpp: attempted to read token from closed stream")
	ErrOutputStreamClosed = errors.New("xmpp: attempted to write token to closed stream")
)

Errors returned by the XMPP package.

Functions

This section is empty.

Types

type Handler

type Handler interface {
	HandleXMPP(t xmlstream.TokenReadEncoder, start *xml.StartElement) error
}

A Handler triggers events or responds to incoming elements in an XML stream.

type HandlerFunc

type HandlerFunc func(t xmlstream.TokenReadEncoder, start *xml.StartElement) error

The HandlerFunc type is an adapter to allow the use of ordinary functions as XMPP handlers. If f is a function with the appropriate signature, HandlerFunc(f) is a Handler that calls f.

func (HandlerFunc) HandleXMPP

func (f HandlerFunc) HandleXMPP(t xmlstream.TokenReadEncoder, start *xml.StartElement) error

HandleXMPP calls f(t, start).

type Negotiator

type Negotiator func(ctx context.Context, in, out *stream.Info, session *Session, data interface{}) (mask SessionState, rw io.ReadWriter, cache interface{}, err error)

Negotiator is a function that can be passed to NewSession to perform custom session negotiation. This can be used for creating custom stream initialization logic that does not use XMPP feature negotiation such as the connection mechanism described in XEP-0114: Jabber Component Protocol.

If a Negotiator is passed into NewSession it will be called repeatedly until a mask is returned with the Ready bit set. When the negotiator reads the new stream start element it should unmarshal the correct values into "in" and set the correct values in "out" for the input and output stream respectively. Each time Negotiator is called any bits set in the state mask that it returns will be set on the session state, and any cache value that is returned will be passed back in during the next iteration. If a new io.ReadWriter is returned, it is set as the session's underlying io.ReadWriter and the internal session state (encoders, decoders, etc.) will be reset.

func NewNegotiator

func NewNegotiator(cfg StreamConfig) Negotiator

NewNegotiator creates a Negotiator that uses a collection of StreamFeatures to negotiate an XMPP client-to-server (c2s) or server-to-server (s2s) session. If StartTLS is one of the supported stream features, the Negotiator attempts to negotiate it whether the server advertises support or not.

type Session

type Session struct {
	// contains filtered or unexported fields
}

A Session represents an XMPP session comprising an input and an output XML stream.

func DialClientSession

func DialClientSession(ctx context.Context, origin jid.JID, features ...StreamFeature) (*Session, error)

DialClientSession uses a default dialer to create a TCP connection and attempts to negotiate an XMPP client-to-server session over it.

If the provided context is canceled after stream negotiation is complete it has no effect on the session.

func DialServerSession

func DialServerSession(ctx context.Context, location, origin jid.JID, features ...StreamFeature) (*Session, error)

DialServerSession uses a default dialer to create a TCP connection and attempts to negotiate an XMPP server-to-server session over it.

If the provided context is canceled after stream negotiation is complete it has no effect on the session.

func DialSession

func DialSession(ctx context.Context, location, origin jid.JID, state SessionState, negotiate Negotiator) (*Session, error)

DialSession uses a default client or server dialer to create a TCP connection and attempts to negotiate an XMPP session over it.

func NewClientSession

func NewClientSession(ctx context.Context, origin jid.JID, rw io.ReadWriter, features ...StreamFeature) (*Session, error)

NewClientSession attempts to use an existing connection (or any io.ReadWriter) to negotiate an XMPP client-to-server session from the initiating client's perspective. If the provided context is canceled before stream negotiation is complete an error is returned. After stream negotiation if the context is canceled it has no effect.

func NewServerSession

func NewServerSession(ctx context.Context, location, origin jid.JID, rw io.ReadWriter, features ...StreamFeature) (*Session, error)

NewServerSession attempts to use an existing connection (or any io.ReadWriter) to negotiate an XMPP server-to-server session from the initiating server's perspective. If the provided context is canceled before stream negotiation is complete an error is returned. After stream negotiation if the context is canceled it has no effect.

func NewSession

func NewSession(ctx context.Context, location, origin jid.JID, rw io.ReadWriter, state SessionState, negotiate Negotiator) (*Session, error)

NewSession creates an XMPP session from the initiating entity's perspective using negotiate to manage the initial handshake. Calling NewSession with a nil Negotiator panics.

For more information see the Negotiator type.

func ReceiveClientSession

func ReceiveClientSession(ctx context.Context, origin jid.JID, rw io.ReadWriter, features ...StreamFeature) (*Session, error)

ReceiveClientSession attempts to use an existing connection (or any io.ReadWriter) to negotiate an XMPP client-to-server session from the server's perspective. If the provided context is canceled before stream negotiation is complete an error is returned. After stream negotiation if the context is canceled it has no effect.

func ReceiveServerSession

func ReceiveServerSession(ctx context.Context, location, origin jid.JID, rw io.ReadWriter, features ...StreamFeature) (*Session, error)

ReceiveServerSession attempts to use an existing connection (or any io.ReadWriter) to negotiate an XMPP server-to-server session from the receiving server's perspective. If the provided context is canceled before stream negotiation is complete an error is returned. After stream negotiation if the context is canceled it has no effect.

func ReceiveSession

func ReceiveSession(ctx context.Context, rw io.ReadWriter, state SessionState, negotiate Negotiator) (*Session, error)

ReceiveSession creates an XMPP session from the receiving server's perspective using negotiate to manage the initial handshake. Calling ReceiveSession with a nil Negotiator panics.

For more information see the Negotiator type.

func (*Session) Close

func (s *Session) Close() error

Close ends the output stream (by sending a closing </stream:stream> token). It does not close the underlying connection. Calling Close() multiple times will only result in one closing </stream:stream> being sent.

func (*Session) Conn

func (s *Session) Conn() net.Conn

Conn returns the Session's backing connection.

This should almost never be read from or written to, but is useful during stream negotiation for wrapping the existing connection in a new layer (eg. compression or TLS).

func (*Session) ConnectionState

func (s *Session) ConnectionState() tls.ConnectionState

ConnectionState returns the underlying connection's TLS state or the zero value if TLS has not been negotiated.

func (*Session) Encode

func (s *Session) Encode(ctx context.Context, v interface{}) error

Encode writes the XML encoding of v to the stream.

For more information see "encoding/xml".Encode.

func (*Session) EncodeElement

func (s *Session) EncodeElement(ctx context.Context, v interface{}, start xml.StartElement) error

EncodeElement writes the XML encoding of v to the stream, using start as the outermost tag in the encoding.

For more information see "encoding/xml".EncodeElement.

func (*Session) EncodeIQ

func (s *Session) EncodeIQ(ctx context.Context, v interface{}) (xmlstream.TokenReadCloser, error)

EncodeIQ is like Encode except that it returns an error if v does not marshal to an IQ stanza and like SendIQ it blocks until a response is received. For more information see SendIQ.

EncodeIQ is safe for concurrent use by multiple goroutines.

func (*Session) EncodeIQElement

func (s *Session) EncodeIQElement(ctx context.Context, payload interface{}, iq stanza.IQ) (xmlstream.TokenReadCloser, error)

EncodeIQElement is like EncodeIQ except that it wraps the payload in an Info/Query (IQ) element. For more information see SendIQ.

EncodeIQElement is safe for concurrent use by multiple goroutines.

func (*Session) Feature

func (s *Session) Feature(namespace string) (data interface{}, ok bool)

Feature checks if a feature with the given namespace was advertised by the server for the current stream. If it was data will be the canonical representation of the feature as returned by the feature's Parse function.

func (*Session) InSID

func (s *Session) InSID() string

InSID returns the stream ID for the input stream.

func (*Session) IterIQ

func (s *Session) IterIQ(ctx context.Context, iq xml.TokenReader) (*xmlstream.Iter, error)

IterIQ is like SendIQ except that error replies are unmarshaled into a stanza.Error and returned and otherwise an iterator over the children of the response payload is returned. For more information see SendIQ.

IterIQ is safe for concurrent use by multiple goroutines.

func (*Session) IterIQElement

func (s *Session) IterIQElement(ctx context.Context, payload xml.TokenReader, iq stanza.IQ) (*xmlstream.Iter, error)

IterIQElement is like IterIQ but it wraps a payload in the provided IQ. For more information see SendIQ.

IterIQElement is safe for concurrent use by multiple goroutines.

func (*Session) LocalAddr

func (s *Session) LocalAddr() jid.JID

LocalAddr returns the Origin address for initiated connections, or the Location for received connections.

func (*Session) OutSID

func (s *Session) OutSID() string

OutSID returns the stream ID for the output stream.

func (*Session) RemoteAddr

func (s *Session) RemoteAddr() jid.JID

RemoteAddr returns the Location address for initiated connections, or the Origin address for received connections.

func (*Session) Send

func (s *Session) Send(ctx context.Context, r xml.TokenReader) error

Send transmits the first element read from the provided token reader.

Send is safe for concurrent use by multiple goroutines.

func (*Session) SendElement

func (s *Session) SendElement(ctx context.Context, r xml.TokenReader, start xml.StartElement) error

SendElement is like Send except that it uses start as the outermost tag in the encoding and uses the entire token stream as the payload.

SendElement is safe for concurrent use by multiple goroutines.

func (*Session) SendIQ

SendIQ is like Send except that it returns an error if the first token read from the stream is not an Info/Query (IQ) start element and blocks until a response is received.

If the input stream is not being processed (a call to Serve is not running), SendIQ will never receive a response and will block until the provided context is canceled. If the response is non-nil, it does not need to be consumed in its entirety, but it must be closed before stream processing will resume. If the IQ type does not require a response—ie. it is a result or error IQ, meaning that it is a response itself—SendIQElemnt does not block and the response is nil.

If the context is closed before the response is received, SendIQ immediately returns the context error. Any response received at a later time will not be associated with the original request but can still be handled by the Serve handler.

If an error is returned, the response will be nil; the converse is not necessarily true. SendIQ is safe for concurrent use by multiple goroutines.

func (*Session) SendIQElement

func (s *Session) SendIQElement(ctx context.Context, payload xml.TokenReader, iq stanza.IQ) (xmlstream.TokenReadCloser, error)

SendIQElement is like SendIQ except that it wraps the payload in an Info/Query (IQ) element. For more information see SendIQ.

SendIQElement is safe for concurrent use by multiple goroutines.

func (*Session) Serve

func (s *Session) Serve(h Handler) (err error)

Serve decodes incoming XML tokens from the connection and delegates handling them to h. If an error is returned from the handler and it is of type stanza.Error or stream.Error, the error is marshaled and sent over the XML stream. If any other error type is returned, it is marshaled as an undefined-condition StreamError. If a stream error is received while serving it is not passed to the handler. Instead, Serve unmarshals the error, closes the session, and returns it (h handles stanza level errors, the session handles stream level errors). If serve handles an incoming IQ stanza and the handler does not write a response (an IQ with the same ID and type "result" or "error"), Serve writes an error IQ with a service-unavailable payload.

If the user closes the output stream by calling Close, Serve continues until the input stream is closed by the remote entity as above, or the deadline set by SetCloseDeadline is reached in which case a timeout error is returned. Serve takes a lock on the input and output stream before calling the handler, so the handler should not close over the session or use any of its send methods or a deadlock will occur. After Serve finishes running the handler, it flushes the output stream.

func (*Session) SetCloseDeadline

func (s *Session) SetCloseDeadline(t time.Time) error

SetCloseDeadline sets a deadline for the input stream to be closed by the other side. If the input stream is not closed by the deadline, the input stream is marked as closed and any blocking calls to Serve will return an error. This is normally called just before a call to Close.

func (*Session) State

func (s *Session) State() SessionState

State returns the current state of the session. For more information, see the SessionState type.

func (*Session) TokenReader

func (s *Session) TokenReader() xmlstream.TokenReadCloser

TokenReader returns a new xmlstream.TokenReadCloser that can be used to read raw XML tokens from the session. All other reads and future calls to TokenReader will block until the Close method is called. After the TokenReadCloser has been closed, any future reads will return io.EOF.

func (*Session) TokenWriter

func (s *Session) TokenWriter() xmlstream.TokenWriteFlushCloser

TokenWriter returns a new xmlstream.TokenWriteCloser that can be used to write raw XML tokens to the session. All other writes and future calls to TokenWriter will block until the Close method is called. After the TokenWriteCloser has been closed, any future writes will return io.EOF.

func (*Session) UnmarshalIQ

func (s *Session) UnmarshalIQ(ctx context.Context, iq xml.TokenReader, v interface{}) error

UnmarshalIQ is like SendIQ except that error replies are unmarshaled into a stanza.Error and returned and otherwise the response payload is unmarshaled into v. For more information see SendIQ.

UnmarshalIQ is safe for concurrent use by multiple goroutines.

func (*Session) UnmarshalIQElement

func (s *Session) UnmarshalIQElement(ctx context.Context, payload xml.TokenReader, iq stanza.IQ, v interface{}) error

UnmarshalIQElement is like UnmarshalIQ but it wraps a payload in the provided IQ. For more information see SendIQ.

UnmarshalIQElement is safe for concurrent use by multiple goroutines.

type SessionState

type SessionState uint8

SessionState is a bitmask that represents the current state of an XMPP session. For a description of each bit, see the various SessionState typed constants.

const (
	// Secure indicates that the underlying connection has been secured. For
	// instance, after STARTTLS has been performed or if a pre-secured connection
	// is being used such as websockets over HTTPS.
	Secure SessionState = 1 << iota

	// Authn indicates that the session has been authenticated (probably with
	// SASL).
	Authn

	// Ready indicates that the session is fully negotiated and that XMPP stanzas
	// may be sent and received.
	Ready

	// Received indicates that the session was initiated by a foreign entity.
	Received

	// OutputStreamClosed indicates that the output stream has been closed with a
	// stream end tag.  When set all write operations will return an error even if
	// the underlying TCP connection is still open.
	OutputStreamClosed

	// InputStreamClosed indicates that the input stream has been closed with a
	// stream end tag. When set all read operations will return an error.
	InputStreamClosed

	// S2S indicates that this is a server-to-server connection.
	S2S
)

func (SessionState) String

func (i SessionState) String() string

type StreamConfig

type StreamConfig struct {
	// The native language of the stream.
	Lang string

	// A list of stream features to attempt to negotiate.
	// Features will be called every time a new stream is started so that the user
	// may look up required stream features based on information about an incoming
	// stream such as the location and origin JID.
	// Individual features still control whether or not they are listed at any
	// given time, so all possible features should be returned on each step and
	// new features only added to the list when we learn that they are possible
	// eg. because the origin or location JID is set and we can look up that users
	// configuration in the database.
	// For example, you would not return StartTLS the first time this feature is
	// called then return Auth once you see that the secure bit is set on the
	// session state because the stream features themselves would handle this for
	// you.
	// Instead you would always return StartTLS and Auth, but you might only add
	// the "password reset" feature once you see that the origin JID is one that
	// has a backup email in the database.
	// The previous stream features list is passed in at each step so that it can
	// be re-used or appended to if desired (however, this is not required).
	Features func(*Session, ...StreamFeature) []StreamFeature

	// WebSocket indicates that the negotiator should use the WebSocket
	// subprotocol defined in RFC 7395.
	WebSocket bool

	// If set a copy of any reads from the session will be written to TeeIn and
	// any writes to the session will be written to TeeOut (similar to the tee(1)
	// command).
	// This can be used to build an "XML console", but users should be careful
	// since this bypasses TLS and could expose passwords and other sensitive
	// data.
	TeeIn, TeeOut io.Writer
}

StreamConfig contains options for configuring the default Negotiator.

type StreamFeature

type StreamFeature struct {
	// The XML name of the feature in the <stream:feature/> list. If a start
	// element with this name is seen while the connection is reading the features
	// list, it will trigger this StreamFeature's Parse function as a callback.
	// If the stream feature is a legacy feature like resource binding that uses
	// an IQ for negotiation, this should be the name of the IQ payload.
	Name xml.Name

	// Bits that are required before this feature is advertised. For instance, if
	// this feature should only be advertised after the user is authenticated we
	// might set this to "Authn" or if it should be advertised only after the
	// feature is authenticated and encrypted we might set this to "Authn|Secure".
	Necessary SessionState

	// Bits that must be off for this feature to be advertised. For instance, if
	// this feature should only be advertised before the connection is
	// authenticated (eg. if the feature performs authentication itself), we might
	// set this to "Authn".
	Prohibited SessionState

	// Used to send the feature in a features list for server connections. The
	// start element will have a name that matches the features name and should be
	// used as the outermost tag in the stream (but also may be ignored).
	List func(ctx context.Context, e xmlstream.TokenWriter, start xml.StartElement) (req bool, err error)

	// Used to parse the feature that begins with the given xml start element
	// (which should have a Name that matches this stream feature's Name).
	// Returns whether or not the feature is required, and any data that will be
	// needed if the feature is selected for negotiation (eg. the list of
	// mechanisms if the feature was SASL authentication).
	Parse func(ctx context.Context, d *xml.Decoder, start *xml.StartElement) (req bool, data interface{}, err error)

	// A function that will take over the session temporarily while negotiating
	// the feature. The "mask" SessionState represents the state bits that should
	// be flipped after negotiation of the feature is complete. For instance, if
	// this feature creates a security layer (such as TLS) and performs
	// authentication, mask would be set to Authn|Secure, but if it does not
	// authenticate the connection it would just return Secure. If negotiate
	// returns a new io.ReadWriter (probably wrapping the old session.Conn()) the
	// stream will be restarted automatically after Negotiate returns using the
	// new ReadWriter. If this is an initiated connection and the features List
	// call returned a value, that value is passed to the data parameter when
	// Negotiate is called. For instance, in the case of compression this data
	// parameter might be the list of supported algorithms as a slice of strings
	// (or in whatever format the feature implementation has decided upon).
	Negotiate func(ctx context.Context, session *Session, data interface{}) (mask SessionState, rw io.ReadWriter, err error)
}

A StreamFeature represents a feature that may be selected during stream negotiation, eg. STARTTLS, compression, and SASL authentication are all stream features. Features should be stateless as they may be reused between connection attempts, however, a method for passing state between features exists on the Parse and Negotiate functions.

func BindCustom

func BindCustom(server func(jid.JID, string) (jid.JID, error)) StreamFeature

BindCustom is identical to BindResource when used on a client session, but for server sessions the server function is called to generate the JID that should be returned to the client. If server is nil, BindCustom is identical to BindResource.

The server function is passed the current client JID and the resource requested by the client (or an empty string if a specific resource was not requested). Resources generated by the server function should be random to prevent certain security issues related to guessing resourceparts.

func BindResource

func BindResource() StreamFeature

BindResource is a stream feature that can be used for binding a resource (the name by which an individual client can be addressed) to the stream.

Resource binding is the final feature negotiated when setting up a new session and is required to allow communication with other clients and servers in the network. Resource binding is mandatory-to-negotiate.

If used on a server connection, BindResource generates and assigns random resourceparts, however this default is subject to change.

func SASL

func SASL(identity, password string, mechanisms ...sasl.Mechanism) StreamFeature

SASL returns a stream feature for performing authentication using the Simple Authentication and Security Layer (SASL) as defined in RFC 4422. It panics if no mechanisms are specified. The order in which mechanisms are specified will be the preferred order, so stronger mechanisms should be listed first.

Identity is used when a user wants to act on behalf of another user. For instance, an admin might want to log in as another user to help them troubleshoot an issue. Normally it is left blank and the localpart of the Origin JID is used.

func SASLServer

func SASLServer(permissions func(*sasl.Negotiator) bool, mechanisms ...sasl.Mechanism) StreamFeature

SASLServer is like SASL but the returned feature uses the provided permissions func to validate credentials provided by the client.

func StartTLS

func StartTLS(cfg *tls.Config) StreamFeature

StartTLS returns a new stream feature that can be used for negotiating TLS. If cfg is nil, a default configuration is used that uses the domainpart of the sessions local address as the ServerName.

Directories

Path Synopsis
Package color implements XEP-0392: Consistent Color Generation v0.4.
Package color implements XEP-0392: Consistent Color Generation v0.4.
Package component is used to establish XEP-0114: Jabber Component Protocol connections.
Package component is used to establish XEP-0114: Jabber Component Protocol connections.
Package compress implements XEP-0138: Stream Compression and XEP-0229: Stream Compression with LZW.
Package compress implements XEP-0138: Stream Compression and XEP-0229: Stream Compression with LZW.
Package delay implements delayed delivery of stanzas.
Package delay implements delayed delivery of stanzas.
Package dial contains methods and types for dialing XMPP connections.
Package dial contains methods and types for dialing XMPP connections.
Package disco implements service discovery.
Package disco implements service discovery.
Package form implements sending and submitting data forms.
Package form implements sending and submitting data forms.
Package forward implements forwarding messages.
Package forward implements forwarding messages.
Package ibr2 implements Extensible In-Band Registration.
Package ibr2 implements Extensible In-Band Registration.
Package jid implements the XMPP address format.
Package jid implements the XMPP address format.
Package mux contains a simple XMPP multiplexer.
Package mux contains a simple XMPP multiplexer.
Package oob implements XEP-0066: Out of Band Data.
Package oob implements XEP-0066: Out of Band Data.
Package paging implements result set management.
Package paging implements result set management.
Package ping implements XEP-0199: XMPP Ping.
Package ping implements XEP-0199: XMPP Ping.
Package receipts implements XEP-0184: Message Delivery Receipts.
Package receipts implements XEP-0184: Message Delivery Receipts.
Package roster implements contact list functionality.
Package roster implements contact list functionality.
Package s2s implements server-to-server functionality.
Package s2s implements server-to-server functionality.
Package stanza contains functionality for dealing with XMPP stanzas and stanza level errors.
Package stanza contains functionality for dealing with XMPP stanzas and stanza level errors.
Package stream implements stream level functionality.
Package stream implements stream level functionality.
Package styling implements XEP-0393: Message Styling, a simple styling language.
Package styling implements XEP-0393: Message Styling, a simple styling language.
Package uri parses XMPP URI and IRI's as defined in RFC 5122.
Package uri parses XMPP URI and IRI's as defined in RFC 5122.
Package version queries a remote entity for software version info.
Package version queries a remote entity for software version info.
Package websocket implements a WebSocket transport for XMPP.
Package websocket implements a WebSocket transport for XMPP.
Package x509 parses X.509-encoded keys and certificates.
Package x509 parses X.509-encoded keys and certificates.
Package xtime implements time related XMPP functionality.
Package xtime implements time related XMPP functionality.
Package internal provides non-exported functionality used by xmpp and its child packages.
Package internal provides non-exported functionality used by xmpp and its child packages.
attr
Package attr contains unexported functionality related to XML attributes.
Package attr contains unexported functionality related to XML attributes.
decl
Package decl contains functionality related to XML declarations.
Package decl contains functionality related to XML declarations.
discover
Package discover is used to look up information about XMPP-based services.
Package discover is used to look up information about XMPP-based services.
integration
Package integration contains helpers for integration testing.
Package integration contains helpers for integration testing.
integration/ejabberd
Package ejabberd facilitates integration testing against Ejabberd.
Package ejabberd facilitates integration testing against Ejabberd.
integration/mcabber
Package mcabber facilitates integration testing against Mcabber.
Package mcabber facilitates integration testing against Mcabber.
integration/mellium
Package mellium facilitates integration testing against clients.
Package mellium facilitates integration testing against clients.
integration/prosody
Package prosody facilitates integration testing against Prosody.
Package prosody facilitates integration testing against Prosody.
integration/sendxmpp
Package sendxmpp facilitates integration testing with sendxmpp.
Package sendxmpp facilitates integration testing with sendxmpp.
marshal
Package marshal contains functions for encoding structs as an XML token stream.
Package marshal contains functions for encoding structs as an XML token stream.
ns
Package ns provides namespace constants that are used by the xmpp package and other internal packages.
Package ns provides namespace constants that are used by the xmpp package and other internal packages.
saslerr
Package saslerr provides error conditions for the XMPP profile of SASL as defined by RFC 6120 §6.5.
Package saslerr provides error conditions for the XMPP profile of SASL as defined by RFC 6120 §6.5.
stream
Package stream contains internal stream parsing and handling behavior.
Package stream contains internal stream parsing and handling behavior.
xmpptest
Package xmpptest provides utilities for XMPP testing.
Package xmpptest provides utilities for XMPP testing.