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