github.com/gdamore/mangos@v1.4.0/protocol.go (about)

     1  // Copyright 2016 The Mangos Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use file except in compliance with the License.
     5  // You may obtain a copy of the license at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package mangos
    16  
    17  import (
    18  	"time"
    19  )
    20  
    21  // Endpoint represents the handle that a Protocol implementation has
    22  // to the underlying stream transport.  It can be thought of as one side
    23  // of a TCP, IPC, or other type of connection.
    24  type Endpoint interface {
    25  	// GetID returns a unique 31-bit value associated with the Endpoint.
    26  	// The value is unique for a given socket, at a given time.
    27  	GetID() uint32
    28  
    29  	// Close does what you think.
    30  	Close() error
    31  
    32  	// SendMsg sends a message.  On success it returns nil. This is a
    33  	// blocking call.
    34  	SendMsg(*Message) error
    35  
    36  	// RecvMsg receives a message.  It blocks until the message is
    37  	// received.  On error, the pipe is closed and nil is returned.
    38  	RecvMsg() *Message
    39  }
    40  
    41  // Protocol implementations handle the "meat" of protocol processing.  Each
    42  // protocol type will implement one of these.  For protocol pairs (REP/REQ),
    43  // there will be one for each half of the protocol.
    44  type Protocol interface {
    45  
    46  	// Init is called by the core to allow the protocol to perform
    47  	// any initialization steps it needs.  It should save the handle
    48  	// for future use, as well.
    49  	Init(ProtocolSocket)
    50  
    51  	// Shutdown is used to drain the send side.  It is only ever called
    52  	// when the socket is being shutdown cleanly. Protocols should use
    53  	// the linger time, and wait up to that time for sockets to drain.
    54  	Shutdown(time.Time)
    55  
    56  	// AddEndpoint is called when a new Endpoint is added to the socket.
    57  	// Typically this is as a result of connect or accept completing.
    58  	AddEndpoint(Endpoint)
    59  
    60  	// RemoveEndpoint is called when an Endpoint is removed from the socket.
    61  	// Typically this indicates a disconnected or closed connection.
    62  	RemoveEndpoint(Endpoint)
    63  
    64  	// ProtocolNumber returns a 16-bit value for the protocol number,
    65  	// as assigned by the SP governing body. (IANA?)
    66  	Number() uint16
    67  
    68  	// Name returns our name.
    69  	Name() string
    70  
    71  	// PeerNumber() returns a 16-bit number for our peer protocol.
    72  	PeerNumber() uint16
    73  
    74  	// PeerName() returns the name of our peer protocol.
    75  	PeerName() string
    76  
    77  	// GetOption is used to retrieve the current value of an option.
    78  	// If the protocol doesn't recognize the option, EBadOption should
    79  	// be returned.
    80  	GetOption(string) (interface{}, error)
    81  
    82  	// SetOption is used to set an option.  EBadOption is returned if
    83  	// the option name is not recognized, EBadValue if the value is
    84  	// invalid.
    85  	SetOption(string, interface{}) error
    86  }
    87  
    88  // The follow are optional interfaces that a Protocol can choose to implement.
    89  
    90  // ProtocolRecvHook is intended to be an additional extension
    91  // to the Protocol interface.
    92  type ProtocolRecvHook interface {
    93  	// RecvHook is called just before the message is handed to the
    94  	// application.  The message may be modified.  If false is returned,
    95  	// then the message is dropped.
    96  	RecvHook(*Message) bool
    97  }
    98  
    99  // ProtocolSendHook is intended to be an additional extension
   100  // to the Protocol interface.
   101  type ProtocolSendHook interface {
   102  	// SendHook is called when the application calls Send.
   103  	// If false is returned, the message will be silently dropped.
   104  	// Note that the message may be dropped for other reasons,
   105  	// such as if backpressure is applied.
   106  	SendHook(*Message) bool
   107  }
   108  
   109  // ProtocolSocket is the "handle" given to protocols to interface with the
   110  // socket.  The Protocol implementation should not access any sockets or pipes
   111  // except by using functions made available on the ProtocolSocket.  Note
   112  // that all functions listed here are non-blocking.
   113  type ProtocolSocket interface {
   114  	// SendChannel represents the channel used to send messages.  The
   115  	// application injects messages to it, and the protocol consumes
   116  	// messages from it.  The channel may be closed when the core needs to
   117  	// create a new channel, typically after an option is set that requires
   118  	// the channel to be reconfigured.  (OptionWriteQLen) When the protocol
   119  	// implementation notices this, it should call this function again to obtain
   120  	// the value of the new channel.
   121  	SendChannel() <-chan *Message
   122  
   123  	// RecvChannel is the channel used to receive messages.  The protocol
   124  	// should inject messages to it, and the application will consume them
   125  	// later.
   126  	RecvChannel() chan<- *Message
   127  
   128  	// The protocol can wait on this channel to close.  When it is closed,
   129  	// it indicates that the application has closed the upper read socket,
   130  	// and the protocol should stop any further read operations on this
   131  	// instance.
   132  	CloseChannel() <-chan struct{}
   133  
   134  	// GetOption may be used by the protocol to retrieve an option from
   135  	// the socket.  This can ultimately wind up calling into the socket's
   136  	// own GetOption handler, so care should be used!
   137  	GetOption(string) (interface{}, error)
   138  
   139  	// SetOption is used by the Protocol to set an option on the socket.
   140  	// Note that this may set transport options, or even call back down
   141  	// into the protocol's own SetOption interface!
   142  	SetOption(string, interface{}) error
   143  
   144  	// SetRecvError is used to cause socket RX callers to report an
   145  	// error.  This can be used to force an error return rather than
   146  	// waiting for a message that will never arrive (e.g. due to state).
   147  	// If set to nil, then RX works normally.
   148  	SetRecvError(error)
   149  
   150  	// SetSendError is used to cause socket TX callers to report an
   151  	// error.  This can be used to force an error return rather than
   152  	// waiting to send a message that will never be delivered (e.g. due
   153  	// to incorrect state.)  If set to nil, then TX works normally.
   154  	SetSendError(error)
   155  }
   156  
   157  // Useful constants for protocol numbers.  Note that the major protocol number
   158  // is stored in the upper 12 bits, and the minor (subprotocol) is located in
   159  // the bottom 4 bits.
   160  const (
   161  	ProtoPair       = (1 * 16)
   162  	ProtoPub        = (2 * 16)
   163  	ProtoSub        = (2 * 16) + 1
   164  	ProtoReq        = (3 * 16)
   165  	ProtoRep        = (3 * 16) + 1
   166  	ProtoPush       = (5 * 16)
   167  	ProtoPull       = (5 * 16) + 1
   168  	ProtoSurveyor   = (6 * 16) + 2
   169  	ProtoRespondent = (6 * 16) + 3
   170  	ProtoBus        = (7 * 16)
   171  
   172  	// Experimental Protocols - Use at Risk
   173  
   174  	ProtoStar = (100 * 16)
   175  )
   176  
   177  // ProtocolName returns the name corresponding to a given protocol number.
   178  // This is useful for transports like WebSocket, which use a text name
   179  // rather than the number in the handshake.
   180  func ProtocolName(number uint16) string {
   181  	names := map[uint16]string{
   182  		ProtoPair:       "pair",
   183  		ProtoPub:        "pub",
   184  		ProtoSub:        "sub",
   185  		ProtoReq:        "req",
   186  		ProtoRep:        "rep",
   187  		ProtoPush:       "push",
   188  		ProtoPull:       "pull",
   189  		ProtoSurveyor:   "surveyor",
   190  		ProtoRespondent: "respondent",
   191  		ProtoBus:        "bus"}
   192  	return names[number]
   193  }
   194  
   195  // ValidPeers returns true if the two sockets are capable of
   196  // peering to one another.  For example, REQ can peer with REP,
   197  // but not with BUS.
   198  func ValidPeers(p1, p2 Protocol) bool {
   199  	if p1.Number() != p2.PeerNumber() {
   200  		return false
   201  	}
   202  	if p2.Number() != p1.PeerNumber() {
   203  		return false
   204  	}
   205  	return true
   206  }
   207  
   208  // NullRecv simply loops, receiving and discarding messages, until the
   209  // Endpoint returns back a nil message.  This allows the Endpoint to notice
   210  // a dropped connection.  It is intended for use by Protocols that are write
   211  // only -- it lets them become aware of a loss of connectivity even when they
   212  // have no data to send.
   213  func NullRecv(ep Endpoint) {
   214  	for {
   215  		var m *Message
   216  		if m = ep.RecvMsg(); m == nil {
   217  			return
   218  		}
   219  		m.Free()
   220  	}
   221  }