Documentation ¶
Overview ¶
Package whisperv5 implements the Whisper protocol (version 5).
Whisper combines aspects of both DHTs and datagram messaging systems (e.g. UDP). As such it may be likened and compared to both, not dissimilar to the matter/energy duality (apologies to physicists for the blatant abuse of a fundamental and beautiful natural principle).
Whisper is a pure identity-based messaging system. Whisper provides a low-level (non-application-specific) but easily-accessible API without being based upon or prejudiced by the low-level hardware attributes and characteristics, particularly the notion of singular endpoints.
Index ¶
- Constants
- Variables
- func BytesToUintBigEndian(b []byte) (res uint64)
- func GenerateRandomID() (id string, err error)
- func IsPubKeyEqual(a, b *ecdsa.PublicKey) bool
- func NewSentMessage(params *MessageParams) (*sentMessage, error)
- func ValidatePublicKey(k *ecdsa.PublicKey) bool
- type Config
- type Criteria
- type Envelope
- func (e *Envelope) DecodeRLP(s *rlp.Stream) error
- func (e *Envelope) Hash() common.Hash
- func (e *Envelope) IsSymmetric() bool
- func (e *Envelope) Open(watcher *Filter) (msg *ReceivedMessage)
- func (e *Envelope) OpenAsymmetric(key *ecdsa.PrivateKey) (*ReceivedMessage, error)
- func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error)
- func (e *Envelope) PoW() float64
- func (e *Envelope) Seal(options *MessageParams) error
- func (e *Envelope) Ver() uint64
- type Filter
- type Filters
- type Info
- type MailServer
- type Message
- type MessageParams
- type NewMessage
- type Peer
- type PublicWhisperAPI
- func (api *PublicWhisperAPI) AddPrivateKey(ctx context.Context, privateKey hexutil.Bytes) (string, error)
- func (api *PublicWhisperAPI) AddSymKey(ctx context.Context, key hexutil.Bytes) (string, error)
- func (api *PublicWhisperAPI) DeleteKeyPair(ctx context.Context, key string) (bool, error)
- func (api *PublicWhisperAPI) DeleteMessageFilter(id string) (bool, error)
- func (api *PublicWhisperAPI) DeleteSymKey(ctx context.Context, id string) bool
- func (api *PublicWhisperAPI) GenerateSymKeyFromPassword(ctx context.Context, passwd string) (string, error)
- func (api *PublicWhisperAPI) GetFilterMessages(id string) ([]*Message, error)
- func (api *PublicWhisperAPI) GetPrivateKey(ctx context.Context, id string) (hexutil.Bytes, error)
- func (api *PublicWhisperAPI) GetPublicKey(ctx context.Context, id string) (hexutil.Bytes, error)
- func (api *PublicWhisperAPI) GetSymKey(ctx context.Context, id string) (hexutil.Bytes, error)
- func (api *PublicWhisperAPI) HasKeyPair(ctx context.Context, id string) bool
- func (api *PublicWhisperAPI) HasSymKey(ctx context.Context, id string) bool
- func (api *PublicWhisperAPI) Info(ctx context.Context) Info
- func (api *PublicWhisperAPI) MarkTrustedPeer(ctx context.Context, url string) (bool, error)
- func (api *PublicWhisperAPI) Messages(ctx context.Context, crit Criteria) (*rpc.Subscription, error)
- func (api *PublicWhisperAPI) NewKeyPair(ctx context.Context) (string, error)
- func (api *PublicWhisperAPI) NewMessageFilter(req Criteria) (string, error)
- func (api *PublicWhisperAPI) NewSymKey(ctx context.Context) (string, error)
- func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, error)
- func (api *PublicWhisperAPI) SetMaxMessageSize(ctx context.Context, size uint32) (bool, error)
- func (api *PublicWhisperAPI) SetMinPoW(ctx context.Context, pow float64) (bool, error)
- func (api *PublicWhisperAPI) Version(ctx context.Context) string
- type ReceivedMessage
- type Statistics
- type TopicType
- type Whisper
- func (w *Whisper) APIs() []rpc.API
- func (w *Whisper) AddKeyPair(key *ecdsa.PrivateKey) (string, error)
- func (w *Whisper) AddSymKeyDirect(key []byte) (string, error)
- func (w *Whisper) AddSymKeyFromPassword(password string) (string, error)
- func (w *Whisper) AllowP2PMessagesFromPeer(peerID []byte) error
- func (w *Whisper) DeleteKeyPair(key string) bool
- func (w *Whisper) DeleteSymKey(id string) bool
- func (w *Whisper) Envelopes() []*Envelope
- func (w *Whisper) GenerateSymKey() (string, error)
- func (w *Whisper) GetFilter(id string) *Filter
- func (w *Whisper) GetPrivateKey(id string) (*ecdsa.PrivateKey, error)
- func (w *Whisper) GetSymKey(id string) ([]byte, error)
- func (w *Whisper) HandlePeer(peer *p2p.Peer, rw p2p.MsgReadWriter) error
- func (w *Whisper) HasKeyPair(id string) bool
- func (w *Whisper) HasSymKey(id string) bool
- func (w *Whisper) MaxMessageSize() uint32
- func (w *Whisper) Messages(id string) []*ReceivedMessage
- func (w *Whisper) MinPow() float64
- func (w *Whisper) NewKeyPair() (string, error)
- func (w *Whisper) Overflow() bool
- func (w *Whisper) Protocols() []p2p.Protocol
- func (w *Whisper) RegisterServer(server MailServer)
- func (w *Whisper) RequestHistoricMessages(peerID []byte, envelope *Envelope) error
- func (w *Whisper) Send(envelope *Envelope) error
- func (w *Whisper) SendP2PDirect(peer *Peer, envelope *Envelope) error
- func (w *Whisper) SendP2PMessage(peerID []byte, envelope *Envelope) error
- func (w *Whisper) SetMaxMessageSize(size uint32) error
- func (w *Whisper) SetMinimumPoW(val float64) error
- func (w *Whisper) Start(*p2p.Server) error
- func (w *Whisper) Stats() Statistics
- func (w *Whisper) Stop() error
- func (w *Whisper) Subscribe(f *Filter) (string, error)
- func (w *Whisper) Unsubscribe(id string) error
- func (w *Whisper) Version() uint
Constants ¶
const ( EnvelopeVersion = uint64(0) ProtocolVersion = uint64(5) ProtocolVersionStr = "5.0" ProtocolName = "shh" NumberOfMessageCodes = 64 TopicLength = 4 AESNonceLength = 12 MaxMessageSize = uint32(10 * 1024 * 1024) // maximum accepted size of a message. DefaultMaxMessageSize = uint32(1024 * 1024) DefaultMinimumPoW = 0.2 DefaultTTL = 50 // seconds SynchAllowance = 10 // seconds )
Variables ¶
var ( ErrSymAsym = errors.New("specify either a symmetric or an asymmetric key") ErrInvalidSymmetricKey = errors.New("invalid symmetric key") ErrInvalidPublicKey = errors.New("invalid public key") ErrInvalidSigningPubKey = errors.New("invalid signing public key") ErrTooLowPoW = errors.New("message rejected, PoW too low") ErrNoTopics = errors.New("missing topic(s)") )
var DefaultConfig = Config{ MaxMessageSize: DefaultMaxMessageSize, MinimumAcceptedPOW: DefaultMinimumPoW, }
Functions ¶
func BytesToUintBigEndian ¶ added in v1.8.24
BytesToUintBigEndian converts the slice to 64-bit unsigned integer.
func GenerateRandomID ¶ added in v1.8.24
GenerateRandomID generates a random string, which is then returned to be used as a key id
func IsPubKeyEqual ¶ added in v1.5.6
func NewSentMessage ¶
func NewSentMessage(params *MessageParams) (*sentMessage, error)
NewSentMessage creates and initializes a non-signed, non-encrypted Whisper message.
func ValidatePublicKey ¶
ValidatePublicKey checks the format of the given public key.
Types ¶
type Criteria ¶ added in v1.8.24
type Criteria struct { SymKeyID string `json:"symKeyID"` PrivateKeyID string `json:"privateKeyID"` Sig []byte `json:"sig"` MinPow float64 `json:"minPow"` Topics []TopicType `json:"topics"` AllowP2P bool `json:"allowP2P"` }
Criteria holds various filter options for inbound messages.
func (Criteria) MarshalJSON ¶ added in v1.8.24
func (*Criteria) UnmarshalJSON ¶ added in v1.8.24
type Envelope ¶
type Envelope struct { Version []byte Expiry uint32 TTL uint32 Topic TopicType AESNonce []byte Data []byte EnvNonce uint64 // contains filtered or unexported fields }
Envelope represents a clear-text data packet to transmit through the Whisper network. Its contents may or may not be encrypted and signed.
func NewEnvelope ¶
NewEnvelope wraps a Whisper message with expiration and destination data included into an envelope for network forwarding.
func (*Envelope) IsSymmetric ¶
func (*Envelope) Open ¶
func (e *Envelope) Open(watcher *Filter) (msg *ReceivedMessage)
Open tries to decrypt an envelope, and populates the message fields in case of success.
func (*Envelope) OpenAsymmetric ¶
func (e *Envelope) OpenAsymmetric(key *ecdsa.PrivateKey) (*ReceivedMessage, error)
OpenAsymmetric tries to decrypt an envelope, potentially encrypted with a particular key.
func (*Envelope) OpenSymmetric ¶
func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error)
OpenSymmetric tries to decrypt an envelope, potentially encrypted with a particular key.
func (*Envelope) Seal ¶
func (e *Envelope) Seal(options *MessageParams) error
Seal closes the envelope by spending the requested amount of time as a proof of work on hashing the data.
type Filter ¶
type Filter struct { Src *ecdsa.PublicKey // Sender of the message KeyAsym *ecdsa.PrivateKey // Private Key of recipient KeySym []byte // Key associated with the Topic Topics [][]byte // Topics to filter messages with PoW float64 // Proof of work as described in the Whisper spec AllowP2P bool // Indicates whether this filter is interested in direct peer-to-peer messages SymKeyHash common.Hash // The Keccak256Hash of the symmetric key, needed for optimization Messages map[common.Hash]*ReceivedMessage // contains filtered or unexported fields }
func (*Filter) MatchEnvelope ¶
func (*Filter) MatchMessage ¶
func (f *Filter) MatchMessage(msg *ReceivedMessage) bool
func (*Filter) MatchTopic ¶ added in v1.5.5
func (*Filter) Retrieve ¶
func (f *Filter) Retrieve() (all []*ReceivedMessage)
func (*Filter) Trigger ¶
func (f *Filter) Trigger(msg *ReceivedMessage)
type Filters ¶
type Filters struct {
// contains filtered or unexported fields
}
func NewFilters ¶
func (*Filters) NotifyWatchers ¶
type Info ¶ added in v1.8.24
type Info struct { Memory int `json:"memory"` // Memory size of the floating messages in bytes. Messages int `json:"messages"` // Number of floating messages. MinPow float64 `json:"minPow"` // Minimal accepted PoW MaxMessageSize uint32 `json:"maxMessageSize"` // Maximum accepted message size }
Info contains diagnostic information.
type MailServer ¶
type MailServer interface { Archive(env *Envelope) DeliverMail(whisperPeer *Peer, request *Envelope) }
MailServer represents a mail server, capable of archiving the old messages for subsequent delivery to the peers. Any implementation must ensure that both functions are thread-safe. Also, they must return ASAP. DeliverMail should use directMessagesCode for delivery, in order to bypass the expiry checks.
type Message ¶ added in v1.8.24
type Message struct { Sig []byte `json:"sig,omitempty"` TTL uint32 `json:"ttl"` Timestamp uint32 `json:"timestamp"` Topic TopicType `json:"topic"` Payload []byte `json:"payload"` Padding []byte `json:"padding"` PoW float64 `json:"pow"` Hash []byte `json:"hash"` Dst []byte `json:"recipientPublicKey,omitempty"` }
Message is the RPC representation of a whisper message.
func ToWhisperMessage ¶ added in v1.8.24
func ToWhisperMessage(message *ReceivedMessage) *Message
ToWhisperMessage converts an internal message into an API version.
func (Message) MarshalJSON ¶ added in v1.8.24
func (*Message) UnmarshalJSON ¶ added in v1.8.24
type MessageParams ¶
type MessageParams struct { TTL uint32 Src *ecdsa.PrivateKey Dst *ecdsa.PublicKey KeySym []byte Topic TopicType WorkTime uint32 PoW float64 Payload []byte Padding []byte }
MessageParams specifies the exact way a message should be wrapped into an Envelope.
type NewMessage ¶ added in v1.8.24
type NewMessage struct { SymKeyID string `json:"symKeyID"` PublicKey []byte `json:"pubKey"` Sig string `json:"sig"` TTL uint32 `json:"ttl"` Topic TopicType `json:"topic"` Payload []byte `json:"payload"` Padding []byte `json:"padding"` PowTime uint32 `json:"powTime"` PowTarget float64 `json:"powTarget"` TargetPeer string `json:"targetPeer"` }
NewMessage represents a new whisper message that is posted through the RPC.
func (NewMessage) MarshalJSON ¶ added in v1.8.24
func (n NewMessage) MarshalJSON() ([]byte, error)
func (*NewMessage) UnmarshalJSON ¶ added in v1.8.24
func (n *NewMessage) UnmarshalJSON(input []byte) error
type Peer ¶
type Peer struct {
// contains filtered or unexported fields
}
Peer represents a whisper protocol peer connection.
type PublicWhisperAPI ¶ added in v1.8.24
type PublicWhisperAPI struct {
// contains filtered or unexported fields
}
PublicWhisperAPI provides the whisper RPC service that can be use publicly without security implications.
func NewPublicWhisperAPI ¶ added in v1.8.24
func NewPublicWhisperAPI(w *Whisper) *PublicWhisperAPI
NewPublicWhisperAPI create a new RPC whisper service.
func (*PublicWhisperAPI) AddPrivateKey ¶ added in v1.8.24
func (api *PublicWhisperAPI) AddPrivateKey(ctx context.Context, privateKey hexutil.Bytes) (string, error)
AddPrivateKey imports the given private key.
func (*PublicWhisperAPI) AddSymKey ¶ added in v1.8.24
AddSymKey import a symmetric key. It returns an ID that can be used to refer to the key. Can be used encrypting and decrypting messages where the key is known to both parties.
func (*PublicWhisperAPI) DeleteKeyPair ¶ added in v1.8.24
DeleteKeyPair removes the key with the given key if it exists.
func (*PublicWhisperAPI) DeleteMessageFilter ¶ added in v1.8.24
func (api *PublicWhisperAPI) DeleteMessageFilter(id string) (bool, error)
DeleteMessageFilter deletes a filter.
func (*PublicWhisperAPI) DeleteSymKey ¶ added in v1.8.24
func (api *PublicWhisperAPI) DeleteSymKey(ctx context.Context, id string) bool
DeleteSymKey deletes the symmetric key that is associated with the given id.
func (*PublicWhisperAPI) GenerateSymKeyFromPassword ¶ added in v1.8.24
func (api *PublicWhisperAPI) GenerateSymKeyFromPassword(ctx context.Context, passwd string) (string, error)
GenerateSymKeyFromPassword derive a key from the given password, stores it, and returns its ID.
func (*PublicWhisperAPI) GetFilterMessages ¶ added in v1.8.24
func (api *PublicWhisperAPI) GetFilterMessages(id string) ([]*Message, error)
GetFilterMessages returns the messages that match the filter criteria and are received between the last poll and now.
func (*PublicWhisperAPI) GetPrivateKey ¶ added in v1.8.24
GetPrivateKey returns the private key associated with the given key. The key is the hex encoded representation of a key in the form specified in section 4.3.6 of ANSI X9.62.
func (*PublicWhisperAPI) GetPublicKey ¶ added in v1.8.24
GetPublicKey returns the public key associated with the given key. The key is the hex encoded representation of a key in the form specified in section 4.3.6 of ANSI X9.62.
func (*PublicWhisperAPI) GetSymKey ¶ added in v1.8.24
GetSymKey returns the symmetric key associated with the given id.
func (*PublicWhisperAPI) HasKeyPair ¶ added in v1.8.24
func (api *PublicWhisperAPI) HasKeyPair(ctx context.Context, id string) bool
HasKeyPair returns an indication if the node has a key pair that is associated with the given id.
func (*PublicWhisperAPI) HasSymKey ¶ added in v1.8.24
func (api *PublicWhisperAPI) HasSymKey(ctx context.Context, id string) bool
HasSymKey returns an indication if the node has a symmetric key associated with the given key.
func (*PublicWhisperAPI) Info ¶ added in v1.8.24
func (api *PublicWhisperAPI) Info(ctx context.Context) Info
Info returns diagnostic information about the whisper node.
func (*PublicWhisperAPI) MarkTrustedPeer ¶ added in v1.8.24
MarkTrustedPeer marks a peer trusted. , which will allow it to send historic (expired) messages. Note: This function is not adding new nodes, the node needs to exists as a peer.
func (*PublicWhisperAPI) Messages ¶ added in v1.8.24
func (api *PublicWhisperAPI) Messages(ctx context.Context, crit Criteria) (*rpc.Subscription, error)
Messages set up a subscription that fires events when messages arrive that match the given set of criteria.
func (*PublicWhisperAPI) NewKeyPair ¶ added in v1.8.24
func (api *PublicWhisperAPI) NewKeyPair(ctx context.Context) (string, error)
NewKeyPair generates a new public and private key pair for message decryption and encryption. It returns an ID that can be used to refer to the keypair.
func (*PublicWhisperAPI) NewMessageFilter ¶ added in v1.8.24
func (api *PublicWhisperAPI) NewMessageFilter(req Criteria) (string, error)
NewMessageFilter creates a new filter that can be used to poll for (new) messages that satisfy the given criteria.
func (*PublicWhisperAPI) NewSymKey ¶ added in v1.8.24
func (api *PublicWhisperAPI) NewSymKey(ctx context.Context) (string, error)
NewSymKey generate a random symmetric key. It returns an ID that can be used to refer to the key. Can be used encrypting and decrypting messages where the key is known to both parties.
func (*PublicWhisperAPI) Post ¶ added in v1.8.24
func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, error)
Post a message on the Whisper network.
func (*PublicWhisperAPI) SetMaxMessageSize ¶ added in v1.8.24
SetMaxMessageSize sets the maximum message size that is accepted. Upper limit is defined in whisperv5.MaxMessageSize.
type ReceivedMessage ¶
type ReceivedMessage struct { Raw []byte Payload []byte Padding []byte Signature []byte PoW float64 // Proof of work as described in the Whisper spec Sent uint32 // Time when the message was posted into the network TTL uint32 // Maximum time to live allowed for the message Src *ecdsa.PublicKey // Message recipient (identity used to decode the message) Dst *ecdsa.PublicKey // Message recipient (identity used to decode the message) Topic TopicType SymKeyHash common.Hash // The Keccak256Hash of the key, associated with the Topic EnvelopeHash common.Hash // Message envelope hash to act as a unique id EnvelopeVersion uint64 }
ReceivedMessage represents a data packet to be received through the Whisper protocol.
func (*ReceivedMessage) SigToPubKey ¶
func (msg *ReceivedMessage) SigToPubKey() *ecdsa.PublicKey
SigToPubKey retrieves the public key of the message signer.
func (*ReceivedMessage) Validate ¶
func (msg *ReceivedMessage) Validate() bool
Validate checks the validity and extracts the fields in case of success
type Statistics ¶ added in v1.8.24
type Statistics struct {
// contains filtered or unexported fields
}
type TopicType ¶
type TopicType [TopicLength]byte
TopicType represents a cryptographically secure, probabilistic partial classifications of a message, determined as the first (left) 4 bytes of the SHA3 hash of some arbitrary data given by the original author of the message.
func BytesToTopic ¶
func (TopicType) MarshalText ¶ added in v1.8.24
MarshalText returns the hex representation of t.
func (*TopicType) UnmarshalText ¶ added in v1.8.24
UnmarshalText parses a hex representation to a topic.
type Whisper ¶
type Whisper struct {
// contains filtered or unexported fields
}
Whisper represents a dark communication interface through the Ethereum network, using its very own P2P communication layer.
func New ¶ added in v1.8.24
New creates a Whisper client ready to communicate through the Ethereum P2P network.
func (*Whisper) APIs ¶ added in v1.8.24
APIs returns the RPC descriptors the Whisper implementation offers
func (*Whisper) AddKeyPair ¶ added in v1.8.24
func (w *Whisper) AddKeyPair(key *ecdsa.PrivateKey) (string, error)
AddKeyPair imports a asymmetric private key and returns it identifier.
func (*Whisper) AddSymKeyDirect ¶ added in v1.8.24
AddSymKeyDirect stores the key, and returns its id.
func (*Whisper) AddSymKeyFromPassword ¶ added in v1.8.24
AddSymKeyFromPassword generates the key from password, stores it, and returns its id.
func (*Whisper) AllowP2PMessagesFromPeer ¶ added in v1.8.24
AllowP2PMessagesFromPeer marks specific peer trusted, which will allow it to send historic (expired) messages.
func (*Whisper) DeleteKeyPair ¶ added in v1.8.24
DeleteKeyPair deletes the specified key if it exists.
func (*Whisper) DeleteSymKey ¶
DeleteSymKey deletes the key associated with the name string if it exists.
func (*Whisper) GenerateSymKey ¶
GenerateSymKey generates a random symmetric key and stores it under id, which is then returned. Will be used in the future for session key exchange.
func (*Whisper) GetPrivateKey ¶ added in v1.8.24
func (w *Whisper) GetPrivateKey(id string) (*ecdsa.PrivateKey, error)
GetPrivateKey retrieves the private key of the specified identity.
func (*Whisper) HandlePeer ¶
HandlePeer is called by the underlying P2P layer when the whisper sub-protocol connection is negotiated.
func (*Whisper) HasKeyPair ¶ added in v1.8.24
HasKeyPair checks if the whisper node is configured with the private key of the specified public pair.
func (*Whisper) HasSymKey ¶
HasSymKey returns true if there is a key associated with the given id. Otherwise returns false.
func (*Whisper) MaxMessageSize ¶ added in v1.8.24
MaxMessageSize returns the maximum accepted message size.
func (*Whisper) Messages ¶
func (w *Whisper) Messages(id string) []*ReceivedMessage
Messages iterates through all currently floating envelopes and retrieves all the messages, that this filter could decrypt.
func (*Whisper) NewKeyPair ¶ added in v1.8.24
NewKeyPair generates a new cryptographic identity for the client, and injects it into the known identities for message decryption. Returns ID of the new key pair.
func (*Whisper) Overflow ¶ added in v1.8.24
Overflow returns an indication if the message queue is full.
func (*Whisper) Protocols ¶
Protocols returns the whisper sub-protocols ran by this particular client.
func (*Whisper) RegisterServer ¶ added in v1.8.24
func (w *Whisper) RegisterServer(server MailServer)
RegisterServer registers MailServer interface. MailServer will process all the incoming messages with p2pRequestCode.
func (*Whisper) RequestHistoricMessages ¶
RequestHistoricMessages sends a message with p2pRequestCode to a specific peer, which is known to implement MailServer interface, and is supposed to process this request and respond with a number of peer-to-peer messages (possibly expired), which are not supposed to be forwarded any further. The whisper protocol is agnostic of the format and contents of envelope.
func (*Whisper) Send ¶
Send injects a message into the whisper send queue, to be distributed in the network in the coming cycles.
func (*Whisper) SendP2PDirect ¶ added in v1.5.11
SendP2PDirect sends a peer-to-peer message to a specific peer.
func (*Whisper) SendP2PMessage ¶
SendP2PMessage sends a peer-to-peer message to a specific peer.
func (*Whisper) SetMaxMessageSize ¶ added in v1.8.24
SetMaxMessageSize sets the maximal message size allowed by this node
func (*Whisper) SetMinimumPoW ¶ added in v1.8.24
SetMinimumPoW sets the minimal PoW required by this node
func (*Whisper) Start ¶
Start implements node.Service, starting the background data propagation thread of the Whisper protocol.
func (*Whisper) Stats ¶ added in v1.8.24
func (w *Whisper) Stats() Statistics
Stats returns the whisper node statistics.
func (*Whisper) Stop ¶
Stop implements node.Service, stopping the background data propagation thread of the Whisper protocol.
func (*Whisper) Subscribe ¶ added in v1.8.24
Subscribe installs a new message handler used for filtering, decrypting and subsequent storing of incoming messages.
func (*Whisper) Unsubscribe ¶ added in v1.8.24
Unsubscribe removes an installed message handler.