go.nanomsg.org/mangos/v3@v3.4.3-0.20240217232803-46464076f1f5/protocol/xpair1/xpair1.go (about)

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