nanomsg.org/go/mangos/v2@v2.0.9-0.20200203084354-8a092611e461/protocol/respondent/respondent.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 respondent implements the RESPONDENT protocol, which is the
    16  // response side of the survey pattern.
    17  package respondent
    18  
    19  import (
    20  	"sync"
    21  	"time"
    22  
    23  	"nanomsg.org/go/mangos/v2/protocol"
    24  )
    25  
    26  // Protocol identity information.
    27  const (
    28  	Self     = protocol.ProtoRespondent
    29  	Peer     = protocol.ProtoSurveyor
    30  	SelfName = "respondent"
    31  	PeerName = "surveyor"
    32  )
    33  
    34  type msg struct {
    35  	m *protocol.Message
    36  	p *pipe
    37  }
    38  
    39  type pipe struct {
    40  	s      *socket
    41  	p      protocol.Pipe
    42  	sendQ  chan *protocol.Message
    43  	closeQ chan struct{}
    44  }
    45  
    46  type socket struct {
    47  	closed   bool
    48  	ttl      int
    49  	sendQLen int
    50  	recvQLen int
    51  	sizeQ    chan struct{}
    52  	recvQ    chan msg
    53  	contexts map[*context]struct{}
    54  	defCtx   *context
    55  	closeQ   chan struct{}
    56  
    57  	sync.Mutex
    58  }
    59  
    60  type context struct {
    61  	s          *socket
    62  	closed     bool
    63  	recvExpire time.Duration
    64  	sendExpire time.Duration
    65  	bestEffort bool
    66  	recvPipe   *pipe
    67  	backtrace  []byte
    68  	closeQ     chan struct{}
    69  }
    70  
    71  const defaultQLen = 128
    72  
    73  // closedQ represents a non-blocking time channel.
    74  var closedQ <-chan time.Time
    75  
    76  // nilQ represents a nil time channel (blocks forever)
    77  var nilQ <-chan time.Time
    78  
    79  func init() {
    80  	tq := make(chan time.Time)
    81  	closedQ = tq
    82  	close(tq)
    83  }
    84  
    85  func (c *context) RecvMsg() (*protocol.Message, error) {
    86  	s := c.s
    87  
    88  	for {
    89  		s.Lock()
    90  		if c.closed {
    91  			s.Unlock()
    92  			return nil, protocol.ErrClosed
    93  		}
    94  		cq := c.closeQ
    95  		tq := nilQ
    96  		rq := s.recvQ
    97  		zq := s.sizeQ
    98  		expTime := c.recvExpire
    99  		c.backtrace = nil
   100  		c.recvPipe = nil
   101  		s.Unlock()
   102  
   103  		if expTime > 0 {
   104  			tq = time.After(expTime)
   105  		}
   106  
   107  		select {
   108  		case msg := <-rq:
   109  			s.Lock()
   110  			c.recvPipe = msg.p
   111  			c.backtrace = append([]byte{}, msg.m.Header...)
   112  			s.Unlock()
   113  			msg.m.Header = nil
   114  			return msg.m, nil
   115  		case <-zq:
   116  			continue
   117  		case <-tq:
   118  			return nil, protocol.ErrRecvTimeout
   119  		case <-cq:
   120  			return nil, protocol.ErrClosed
   121  		}
   122  	}
   123  }
   124  
   125  func (c *context) SendMsg(m *protocol.Message) error {
   126  
   127  	s := c.s
   128  	s.Lock()
   129  	if s.closed || c.closed {
   130  		s.Unlock()
   131  		return protocol.ErrClosed
   132  	}
   133  	if c.backtrace == nil {
   134  		s.Unlock()
   135  		return protocol.ErrProtoState
   136  	}
   137  	p := c.recvPipe
   138  	bt := c.backtrace
   139  	c.backtrace = nil
   140  	c.recvPipe = nil
   141  	bestEffort := c.bestEffort
   142  	tq := nilQ
   143  	cq := c.closeQ
   144  	s.Unlock()
   145  
   146  	if bestEffort {
   147  		tq = closedQ
   148  	} else if c.sendExpire > 0 {
   149  		tq = time.After(c.sendExpire)
   150  	}
   151  
   152  	m.Header = bt
   153  
   154  	select {
   155  	case <-cq:
   156  		m.Header = nil
   157  		return protocol.ErrClosed
   158  	case <-p.closeQ:
   159  		// Pipe closed, so no way to get it to the recipient.
   160  		// Just discard the message.
   161  		m.Free()
   162  		return nil
   163  	case <-tq:
   164  		if bestEffort {
   165  			m.Free()
   166  			return nil
   167  		}
   168  		m.Header = nil
   169  		return protocol.ErrSendTimeout
   170  
   171  	case p.sendQ <- m:
   172  		return nil
   173  	}
   174  }
   175  
   176  func (c *context) close() {
   177  	if !c.closed {
   178  		delete(c.s.contexts, c)
   179  		c.closed = true
   180  		close(c.closeQ)
   181  	}
   182  }
   183  
   184  func (c *context) Close() error {
   185  	s := c.s
   186  	s.Lock()
   187  	defer s.Unlock()
   188  	if c.closed {
   189  		return protocol.ErrClosed
   190  	}
   191  	c.close()
   192  	return nil
   193  }
   194  
   195  func (c *context) GetOption(name string) (interface{}, error) {
   196  	switch name {
   197  	case protocol.OptionBestEffort:
   198  		c.s.Lock()
   199  		v := c.bestEffort
   200  		c.s.Unlock()
   201  		return v, nil
   202  
   203  	case protocol.OptionRecvDeadline:
   204  		c.s.Lock()
   205  		v := c.recvExpire
   206  		c.s.Unlock()
   207  		return v, nil
   208  
   209  	case protocol.OptionSendDeadline:
   210  		c.s.Lock()
   211  		v := c.sendExpire
   212  		c.s.Unlock()
   213  		return v, nil
   214  
   215  	default:
   216  		return nil, protocol.ErrBadOption
   217  	}
   218  }
   219  
   220  func (c *context) SetOption(name string, v interface{}) error {
   221  	switch name {
   222  	case protocol.OptionSendDeadline:
   223  		if val, ok := v.(time.Duration); ok && val.Nanoseconds() > 0 {
   224  			c.s.Lock()
   225  			c.sendExpire = val
   226  			c.s.Unlock()
   227  			return nil
   228  		}
   229  		return protocol.ErrBadValue
   230  
   231  	case protocol.OptionRecvDeadline:
   232  		if val, ok := v.(time.Duration); ok && val.Nanoseconds() > 0 {
   233  			c.s.Lock()
   234  			c.recvExpire = val
   235  			c.s.Unlock()
   236  			return nil
   237  		}
   238  		return protocol.ErrBadValue
   239  
   240  	case protocol.OptionBestEffort:
   241  		if val, ok := v.(bool); ok {
   242  			c.s.Lock()
   243  			c.bestEffort = val
   244  			c.s.Unlock()
   245  			return nil
   246  		}
   247  		return protocol.ErrBadValue
   248  
   249  	default:
   250  		return protocol.ErrBadOption
   251  	}
   252  }
   253  
   254  func (p *pipe) receiver() {
   255  	s := p.s
   256  outer:
   257  	for {
   258  		m := p.p.RecvMsg()
   259  		if m == nil {
   260  			break
   261  		}
   262  
   263  		// Move backtrace from body to header.
   264  		hops := 0
   265  		for {
   266  			if hops >= s.ttl {
   267  				m.Free() // ErrTooManyHops
   268  				continue outer
   269  			}
   270  			hops++
   271  			if len(m.Body) < 4 {
   272  				m.Free() // ErrGarbled
   273  				continue outer
   274  			}
   275  			m.Header = append(m.Header, m.Body[:4]...)
   276  			m.Body = m.Body[4:]
   277  			// Check for high order bit set (0x80000000, big endian)
   278  			if m.Header[len(m.Header)-4]&0x80 != 0 {
   279  				// Protocol error from partner, discard and
   280  				// close the pipe.
   281  				break
   282  			}
   283  		}
   284  		msg := msg{
   285  			m: m,
   286  			p: p,
   287  		}
   288  
   289  	inner:
   290  		for {
   291  			s.Lock()
   292  			rq := s.recvQ
   293  			cq := s.closeQ
   294  			zq := s.sizeQ
   295  			s.Unlock()
   296  
   297  			select {
   298  			case <-zq:
   299  				continue inner
   300  			case rq <- msg:
   301  				break inner
   302  			case <-cq:
   303  				m.Free()
   304  				break outer
   305  			}
   306  		}
   307  	}
   308  	go p.close()
   309  }
   310  
   311  func (p *pipe) sender() {
   312  	for {
   313  		select {
   314  		case m := <-p.sendQ:
   315  			if p.p.SendMsg(m) != nil {
   316  				p.close()
   317  				return
   318  			}
   319  		case <-p.closeQ:
   320  			return
   321  		}
   322  	}
   323  }
   324  
   325  func (p *pipe) close() {
   326  	_ = p.p.Close()
   327  }
   328  
   329  func (s *socket) Close() error {
   330  
   331  	s.Lock()
   332  	defer s.Unlock()
   333  
   334  	if s.closed {
   335  		return protocol.ErrClosed
   336  	}
   337  	s.closed = true
   338  	close(s.closeQ)
   339  	for c := range s.contexts {
   340  		c.close()
   341  	}
   342  	return nil
   343  }
   344  
   345  func (*socket) Info() protocol.Info {
   346  	return protocol.Info{
   347  		Self:     Self,
   348  		Peer:     Peer,
   349  		SelfName: SelfName,
   350  		PeerName: PeerName,
   351  	}
   352  }
   353  
   354  func (s *socket) AddPipe(pp protocol.Pipe) error {
   355  
   356  	p := &pipe{
   357  		p:      pp,
   358  		s:      s,
   359  		sendQ:  make(chan *protocol.Message, s.sendQLen),
   360  		closeQ: make(chan struct{}),
   361  	}
   362  	pp.SetPrivate(p)
   363  	s.Lock()
   364  	if s.closed {
   365  		s.Unlock()
   366  		return protocol.ErrClosed
   367  	}
   368  	go p.sender()
   369  	go p.receiver()
   370  	s.Unlock()
   371  	return nil
   372  }
   373  
   374  func (s *socket) RemovePipe(pp protocol.Pipe) {
   375  
   376  	p := pp.GetPrivate().(*pipe)
   377  	close(p.closeQ)
   378  }
   379  
   380  func (s *socket) SetOption(name string, v interface{}) error {
   381  	switch name {
   382  	case protocol.OptionWriteQLen:
   383  		if qLen, ok := v.(int); ok && qLen >= 0 {
   384  			s.Lock()
   385  			s.sendQLen = qLen
   386  			s.Unlock()
   387  			return nil
   388  		}
   389  		return protocol.ErrBadValue
   390  
   391  	case protocol.OptionReadQLen:
   392  		if qLen, ok := v.(int); ok && qLen >= 0 {
   393  
   394  			newQ := make(chan msg, qLen)
   395  			s.Lock()
   396  			sizeQ := s.sizeQ
   397  			s.sizeQ = make(chan struct{})
   398  			s.recvQ = newQ
   399  			s.recvQLen = qLen
   400  			s.Unlock()
   401  
   402  			// Close the sizeQ to let anyone watching know that
   403  			// they should re-examine the recvQ.
   404  			close(sizeQ)
   405  			return nil
   406  		}
   407  		return protocol.ErrBadValue
   408  
   409  	case protocol.OptionTTL:
   410  		if ttl, ok := v.(int); ok && ttl > 0 && ttl < 256 {
   411  			s.Lock()
   412  			s.ttl = ttl
   413  			s.Unlock()
   414  			return nil
   415  		}
   416  		return protocol.ErrBadValue
   417  	}
   418  	return s.defCtx.SetOption(name, v)
   419  }
   420  
   421  func (s *socket) GetOption(name string) (interface{}, error) {
   422  	switch name {
   423  	case protocol.OptionRaw:
   424  		return false, nil
   425  	case protocol.OptionTTL:
   426  		s.Lock()
   427  		v := s.ttl
   428  		s.Unlock()
   429  		return v, nil
   430  	case protocol.OptionWriteQLen:
   431  		s.Lock()
   432  		v := s.sendQLen
   433  		s.Unlock()
   434  		return v, nil
   435  
   436  	case protocol.OptionReadQLen:
   437  		s.Lock()
   438  		v := s.recvQLen
   439  		s.Unlock()
   440  		return v, nil
   441  	}
   442  
   443  	return s.defCtx.GetOption(name)
   444  }
   445  
   446  func (s *socket) OpenContext() (protocol.Context, error) {
   447  	s.Lock()
   448  	defer s.Unlock()
   449  	if s.closed {
   450  		return nil, protocol.ErrClosed
   451  	}
   452  	c := &context{
   453  		s:          s,
   454  		closeQ:     make(chan struct{}),
   455  		bestEffort: s.defCtx.bestEffort,
   456  		recvExpire: s.defCtx.recvExpire,
   457  		sendExpire: s.defCtx.sendExpire,
   458  	}
   459  	s.contexts[c] = struct{}{}
   460  	return c, nil
   461  }
   462  
   463  func (s *socket) RecvMsg() (*protocol.Message, error) {
   464  	return s.defCtx.RecvMsg()
   465  }
   466  
   467  func (s *socket) SendMsg(m *protocol.Message) error {
   468  	return s.defCtx.SendMsg(m)
   469  }
   470  
   471  // NewProtocol allocates a protocol state for the RESPONDENT protocol.
   472  func NewProtocol() protocol.Protocol {
   473  	s := &socket{
   474  		ttl:      8,
   475  		contexts: make(map[*context]struct{}),
   476  		recvQLen: defaultQLen,
   477  		recvQ:    make(chan msg, defaultQLen),
   478  		closeQ:   make(chan struct{}),
   479  		sizeQ:    make(chan struct{}),
   480  		defCtx: &context{
   481  			closeQ: make(chan struct{}),
   482  		},
   483  	}
   484  	s.defCtx.s = s
   485  	s.contexts[s.defCtx] = struct{}{}
   486  	return s
   487  }
   488  
   489  // NewSocket allocates a new Socket using the REP protocol.
   490  func NewSocket() (protocol.Socket, error) {
   491  	return protocol.MakeSocket(NewProtocol()), nil
   492  }