nanomsg.org/go/mangos/v2@v2.0.9-0.20200203084354-8a092611e461/protocol/xrep/xrep.go (about)

     1  // Copyright 2019 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 xrep implements the raw REP protocol, which is the response side of
    16  // the request/response pattern.  (REQ is the request.)
    17  package xrep
    18  
    19  import (
    20  	"encoding/binary"
    21  	"sync"
    22  	"time"
    23  
    24  	"nanomsg.org/go/mangos/v2/protocol"
    25  )
    26  
    27  // Protocol identity information.
    28  const (
    29  	Self     = protocol.ProtoRep
    30  	Peer     = protocol.ProtoReq
    31  	SelfName = "rep"
    32  	PeerName = "req"
    33  )
    34  
    35  type pipe struct {
    36  	p      protocol.Pipe
    37  	s      *socket
    38  	closeQ chan struct{}
    39  	sendQ  chan *protocol.Message
    40  }
    41  
    42  type socket struct {
    43  	closed     bool
    44  	closeQ     chan struct{}
    45  	sizeQ      chan struct{}
    46  	recvQ      chan *protocol.Message
    47  	pipes      map[uint32]*pipe
    48  	recvExpire time.Duration
    49  	sendExpire time.Duration
    50  	sendQLen   int
    51  	recvQLen   int
    52  	bestEffort bool
    53  	ttl        int
    54  	sync.Mutex
    55  }
    56  
    57  var (
    58  	nilQ    <-chan time.Time
    59  	closedQ chan time.Time
    60  )
    61  
    62  const defaultQLen = 128
    63  
    64  func init() {
    65  	closedQ = make(chan time.Time)
    66  	close(closedQ)
    67  }
    68  
    69  // SendMessage implements sending a message.  The message must already
    70  // have headers... the first 4 bytes are the identity of the pipe
    71  // we should send to.
    72  func (s *socket) SendMsg(m *protocol.Message) error {
    73  
    74  	s.Lock()
    75  
    76  	if s.closed {
    77  		s.Unlock()
    78  		return protocol.ErrClosed
    79  	}
    80  
    81  	if len(m.Header) < 4 {
    82  		s.Unlock()
    83  		m.Free()
    84  		return nil
    85  	}
    86  
    87  	id := binary.BigEndian.Uint32(m.Header)
    88  	hdr := m.Header
    89  	m.Header = m.Header[4:]
    90  
    91  	bestEffort := s.bestEffort
    92  	tq := nilQ
    93  	p, ok := s.pipes[id]
    94  	if !ok {
    95  		s.Unlock()
    96  		m.Free()
    97  		return nil
    98  	}
    99  	if bestEffort {
   100  		tq = closedQ
   101  	} else if s.sendExpire > 0 {
   102  		tq = time.After(s.sendExpire)
   103  	}
   104  	s.Unlock()
   105  
   106  	select {
   107  	case p.sendQ <- m:
   108  		return nil
   109  	case <-p.closeQ:
   110  		// restore the header
   111  		m.Header = hdr
   112  		return protocol.ErrClosed
   113  	case <-tq:
   114  		if bestEffort {
   115  			m.Free()
   116  			return nil
   117  		}
   118  		// restore the header
   119  		m.Header = hdr
   120  		return protocol.ErrSendTimeout
   121  	}
   122  }
   123  
   124  func (s *socket) RecvMsg() (*protocol.Message, error) {
   125  	for {
   126  		s.Lock()
   127  		timeQ := nilQ
   128  		recvQ := s.recvQ
   129  		sizeQ := s.sizeQ
   130  		closeQ := s.closeQ
   131  		if s.recvExpire > 0 {
   132  			timeQ = time.After(s.recvExpire)
   133  		}
   134  		s.Unlock()
   135  		select {
   136  		case <-closeQ:
   137  			return nil, protocol.ErrClosed
   138  		case <-timeQ:
   139  			return nil, protocol.ErrRecvTimeout
   140  		case m := <-recvQ:
   141  			return m, nil
   142  		case <-sizeQ:
   143  		}
   144  	}
   145  }
   146  
   147  func (p *pipe) receiver() {
   148  	s := p.s
   149  outer:
   150  	for {
   151  		m := p.p.RecvMsg()
   152  		if m == nil {
   153  			break
   154  		}
   155  
   156  		// Outer most value of header is pipe ID
   157  		m.Header = append(make([]byte, 4), m.Header...)
   158  		binary.BigEndian.PutUint32(m.Header, p.p.ID())
   159  
   160  		s.Lock()
   161  		ttl := s.ttl
   162  		recvQ := s.recvQ
   163  		sizeQ := s.sizeQ
   164  		s.Unlock()
   165  
   166  		hops := 1
   167  		finish := false
   168  		for !finish {
   169  			if hops > ttl {
   170  				m.Free()
   171  				continue outer
   172  			}
   173  			hops++
   174  			if len(m.Body) < 4 {
   175  				m.Free() // Garbled!
   176  				continue outer
   177  			}
   178  			if m.Body[0]&0x80 != 0 {
   179  				// High order bit set indicates ID and end of
   180  				// message headers.
   181  				finish = true
   182  			}
   183  			m.Header = append(m.Header, m.Body[:4]...)
   184  			m.Body = m.Body[4:]
   185  		}
   186  
   187  		select {
   188  		case recvQ <- m:
   189  			continue
   190  		case <-sizeQ:
   191  			continue
   192  		case <-p.closeQ:
   193  			m.Free()
   194  			break outer
   195  		}
   196  	}
   197  	go p.close()
   198  }
   199  
   200  // This is a puller, and doesn't permit for priorities.  We might want
   201  // to refactor this to use a push based scheme later.
   202  func (p *pipe) sender() {
   203  outer:
   204  	for {
   205  		var m *protocol.Message
   206  		select {
   207  		case m = <-p.sendQ:
   208  		case <-p.closeQ:
   209  			break outer
   210  		}
   211  
   212  		if e := p.p.SendMsg(m); e != nil {
   213  			break
   214  		}
   215  	}
   216  	go p.close()
   217  }
   218  
   219  func (p *pipe) close() {
   220  	_ = p.p.Close()
   221  }
   222  
   223  func (s *socket) SetOption(name string, value interface{}) error {
   224  	switch name {
   225  
   226  	case protocol.OptionTTL:
   227  		if v, ok := value.(int); ok && v > 0 && v < 256 {
   228  			s.Lock()
   229  			s.ttl = v
   230  			s.Unlock()
   231  			return nil
   232  		}
   233  		return protocol.ErrBadValue
   234  
   235  	case protocol.OptionRecvDeadline:
   236  		if v, ok := value.(time.Duration); ok {
   237  			s.Lock()
   238  			s.recvExpire = v
   239  			s.Unlock()
   240  			return nil
   241  		}
   242  		return protocol.ErrBadValue
   243  
   244  	case protocol.OptionSendDeadline:
   245  		if v, ok := value.(time.Duration); ok {
   246  			s.Lock()
   247  			s.sendExpire = v
   248  			s.Unlock()
   249  			return nil
   250  		}
   251  		return protocol.ErrBadValue
   252  
   253  	case protocol.OptionBestEffort:
   254  		if v, ok := value.(bool); ok {
   255  			s.Lock()
   256  			s.bestEffort = v
   257  			s.Unlock()
   258  			return nil
   259  		}
   260  		return protocol.ErrBadValue
   261  
   262  	case protocol.OptionWriteQLen:
   263  		if v, ok := value.(int); ok && v >= 0 {
   264  			s.Lock()
   265  			// This does not impact pipes already connected.
   266  			s.sendQLen = v
   267  			s.Unlock()
   268  			return nil
   269  		}
   270  		return protocol.ErrBadValue
   271  
   272  	case protocol.OptionReadQLen:
   273  		if v, ok := value.(int); ok && v >= 0 {
   274  			recvQ := make(chan *protocol.Message, v)
   275  			sizeQ := make(chan struct{})
   276  			s.Lock()
   277  			s.recvQLen = v
   278  			s.recvQ = recvQ
   279  			sizeQ, s.sizeQ = s.sizeQ, sizeQ
   280  			s.Unlock()
   281  			close(sizeQ)
   282  			return nil
   283  		}
   284  		return protocol.ErrBadValue
   285  	}
   286  
   287  	return protocol.ErrBadOption
   288  }
   289  
   290  func (s *socket) GetOption(option string) (interface{}, error) {
   291  	switch option {
   292  	case protocol.OptionRaw:
   293  		return true, nil
   294  	case protocol.OptionTTL:
   295  		s.Lock()
   296  		v := s.ttl
   297  		s.Unlock()
   298  		return v, nil
   299  	case protocol.OptionRecvDeadline:
   300  		s.Lock()
   301  		v := s.recvExpire
   302  		s.Unlock()
   303  		return v, nil
   304  	case protocol.OptionSendDeadline:
   305  		s.Lock()
   306  		v := s.sendExpire
   307  		s.Unlock()
   308  		return v, nil
   309  	case protocol.OptionBestEffort:
   310  		s.Lock()
   311  		v := s.bestEffort
   312  		s.Unlock()
   313  		return v, nil
   314  	case protocol.OptionWriteQLen:
   315  		s.Lock()
   316  		v := s.sendQLen
   317  		s.Unlock()
   318  		return v, nil
   319  	case protocol.OptionReadQLen:
   320  		s.Lock()
   321  		v := s.recvQLen
   322  		s.Unlock()
   323  		return v, nil
   324  	}
   325  
   326  	return nil, protocol.ErrBadOption
   327  }
   328  
   329  func (s *socket) Close() error {
   330  	s.Lock()
   331  	if s.closed {
   332  		s.Unlock()
   333  		return protocol.ErrClosed
   334  	}
   335  	s.closed = true
   336  	s.Unlock()
   337  	close(s.closeQ)
   338  	return nil
   339  }
   340  
   341  func (s *socket) AddPipe(pp protocol.Pipe) error {
   342  	p := &pipe{
   343  		p:      pp,
   344  		s:      s,
   345  		closeQ: make(chan struct{}),
   346  		sendQ:  make(chan *protocol.Message, s.sendQLen),
   347  	}
   348  	pp.SetPrivate(p)
   349  	s.Lock()
   350  	defer s.Unlock()
   351  	if s.closed {
   352  		return protocol.ErrClosed
   353  	}
   354  	s.pipes[pp.ID()] = p
   355  	go p.sender()
   356  	go p.receiver()
   357  	return nil
   358  }
   359  
   360  func (s *socket) RemovePipe(pp protocol.Pipe) {
   361  	p := pp.GetPrivate().(*pipe)
   362  	close(p.closeQ)
   363  
   364  	s.Lock()
   365  	delete(s.pipes, p.p.ID())
   366  	s.Unlock()
   367  }
   368  
   369  func (s *socket) OpenContext() (protocol.Context, error) {
   370  	return nil, protocol.ErrProtoOp
   371  }
   372  
   373  func (*socket) Info() protocol.Info {
   374  	return protocol.Info{
   375  		Self:     Self,
   376  		Peer:     Peer,
   377  		SelfName: SelfName,
   378  		PeerName: PeerName,
   379  	}
   380  }
   381  
   382  // NewProtocol returns a new protocol implementation.
   383  func NewProtocol() protocol.Protocol {
   384  	s := &socket{
   385  		pipes:    make(map[uint32]*pipe),
   386  		closeQ:   make(chan struct{}),
   387  		sizeQ:    make(chan struct{}),
   388  		recvQ:    make(chan *protocol.Message, defaultQLen),
   389  		sendQLen: defaultQLen,
   390  		recvQLen: defaultQLen,
   391  		ttl:      8,
   392  	}
   393  	return s
   394  }
   395  
   396  // NewSocket allocates a new Socket using the REP protocol.
   397  func NewSocket() (protocol.Socket, error) {
   398  	return protocol.MakeSocket(NewProtocol()), nil
   399  }