nanomsg.org/go/mangos/v2@v2.0.9-0.20200203084354-8a092611e461/protocol/xstar/xstar.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 xstar implements the experimental star protocol. This sends messages
    16  // out to all peers, and receives their responses.  It also implicitly resends
    17  // any message it receives to all of its peers, but it will not rebroadcast
    18  // a message to the peer it was received from.
    19  package xstar
    20  
    21  import (
    22  	"sync"
    23  	"time"
    24  
    25  	"nanomsg.org/go/mangos/v2/protocol"
    26  )
    27  
    28  // Protocol identity information.
    29  const (
    30  	Self     = protocol.ProtoStar
    31  	Peer     = protocol.ProtoStar
    32  	SelfName = "star"
    33  	PeerName = "star"
    34  )
    35  
    36  type pipe struct {
    37  	p      protocol.Pipe
    38  	s      *socket
    39  	closeq chan struct{}
    40  	sendq  chan *protocol.Message
    41  }
    42  
    43  type socket struct {
    44  	closed     bool
    45  	closeq     chan struct{}
    46  	pipes      map[uint32]*pipe
    47  	recvQLen   int
    48  	sendQLen   int
    49  	recvExpire time.Duration
    50  	recvq      chan *protocol.Message
    51  	ttl        int
    52  	sync.Mutex
    53  }
    54  
    55  var (
    56  	nilQ <-chan time.Time
    57  )
    58  
    59  const defaultQLen = 128
    60  
    61  func (s *socket) SendMsg(m *protocol.Message) error {
    62  	s.Lock()
    63  	if s.closed {
    64  		s.Unlock()
    65  		return protocol.ErrClosed
    66  	}
    67  
    68  	// Raw mode messages are required to come wth the header.
    69  	if len(m.Header) != 4 {
    70  		s.Unlock()
    71  		m.Free()
    72  		return nil
    73  	}
    74  
    75  	for _, p := range s.pipes {
    76  
    77  		m.Clone()
    78  		select {
    79  		case p.sendq <- m:
    80  		default:
    81  			// back-pressure, but we do not exert
    82  			m.Free()
    83  		}
    84  	}
    85  	s.Unlock()
    86  	m.Free()
    87  	return nil
    88  }
    89  
    90  func (s *socket) RecvMsg() (*protocol.Message, error) {
    91  	// For now this uses a simple unified queue for the entire
    92  	// socket.  Later we can look at moving this to priority queues
    93  	// based on socket pipes.
    94  	tq := nilQ
    95  	s.Lock()
    96  	if s.recvExpire > 0 {
    97  		tq = time.After(s.recvExpire)
    98  	}
    99  	s.Unlock()
   100  	select {
   101  	case <-s.closeq:
   102  		return nil, protocol.ErrClosed
   103  	case <-tq:
   104  		return nil, protocol.ErrRecvTimeout
   105  	case m := <-s.recvq:
   106  		return m, nil
   107  	}
   108  }
   109  
   110  func (s *socket) SetOption(name string, value interface{}) error {
   111  	switch name {
   112  
   113  	case protocol.OptionTTL:
   114  		if v, ok := value.(int); ok && v > 0 && v < 256 {
   115  			s.Lock()
   116  			s.ttl = v
   117  			s.Unlock()
   118  			return nil
   119  		}
   120  		return protocol.ErrBadValue
   121  
   122  	case protocol.OptionRecvDeadline:
   123  		if v, ok := value.(time.Duration); ok {
   124  			s.Lock()
   125  			s.recvExpire = v
   126  			s.Unlock()
   127  			return nil
   128  		}
   129  		return protocol.ErrBadValue
   130  
   131  	case protocol.OptionWriteQLen:
   132  		if v, ok := value.(int); ok && v >= 0 {
   133  			s.Lock()
   134  			s.sendQLen = v
   135  			s.Unlock()
   136  			return nil
   137  		}
   138  		return protocol.ErrBadValue
   139  
   140  	case protocol.OptionReadQLen:
   141  		if v, ok := value.(int); ok && v >= 0 {
   142  			newchan := make(chan *protocol.Message, v)
   143  			s.Lock()
   144  			s.recvQLen = v
   145  			s.recvq = newchan
   146  			s.Unlock()
   147  
   148  			return nil
   149  		}
   150  		return protocol.ErrBadValue
   151  	}
   152  
   153  	return protocol.ErrBadOption
   154  }
   155  
   156  func (s *socket) GetOption(option string) (interface{}, error) {
   157  	switch option {
   158  	case protocol.OptionRaw:
   159  		return true, nil
   160  	case protocol.OptionTTL:
   161  		s.Lock()
   162  		v := s.ttl
   163  		s.Unlock()
   164  		return v, nil
   165  	case protocol.OptionRecvDeadline:
   166  		s.Lock()
   167  		v := s.recvExpire
   168  		s.Unlock()
   169  		return v, nil
   170  	case protocol.OptionWriteQLen:
   171  		s.Lock()
   172  		v := s.sendQLen
   173  		s.Unlock()
   174  		return v, nil
   175  	case protocol.OptionReadQLen:
   176  		s.Lock()
   177  		v := s.recvQLen
   178  		s.Unlock()
   179  		return v, nil
   180  	}
   181  
   182  	return nil, protocol.ErrBadOption
   183  }
   184  
   185  func (s *socket) AddPipe(pp protocol.Pipe) error {
   186  	p := &pipe{
   187  		p:      pp,
   188  		s:      s,
   189  		closeq: make(chan struct{}),
   190  		sendq:  make(chan *protocol.Message, s.sendQLen),
   191  	}
   192  	pp.SetPrivate(p)
   193  	s.Lock()
   194  	defer s.Unlock()
   195  	if s.closed {
   196  		return protocol.ErrClosed
   197  	}
   198  	s.pipes[pp.ID()] = p
   199  
   200  	go p.sender()
   201  	go p.receiver()
   202  	return nil
   203  }
   204  
   205  func (s *socket) RemovePipe(pp protocol.Pipe) {
   206  	p := pp.GetPrivate().(*pipe)
   207  	close(p.closeq)
   208  	s.Lock()
   209  	delete(p.s.pipes, p.p.ID())
   210  	s.Unlock()
   211  }
   212  
   213  func (s *socket) OpenContext() (protocol.Context, error) {
   214  	return nil, protocol.ErrProtoOp
   215  }
   216  
   217  func (*socket) Info() protocol.Info {
   218  	return protocol.Info{
   219  		Self:     Self,
   220  		Peer:     Peer,
   221  		SelfName: SelfName,
   222  		PeerName: PeerName,
   223  	}
   224  }
   225  
   226  func (s *socket) Close() error {
   227  	s.Lock()
   228  	if s.closed {
   229  		s.Unlock()
   230  		return protocol.ErrClosed
   231  	}
   232  	s.closed = true
   233  	s.Unlock()
   234  
   235  	close(s.closeq)
   236  	return nil
   237  }
   238  
   239  func (p *pipe) sender() {
   240  outer:
   241  	for {
   242  		var m *protocol.Message
   243  		select {
   244  		case <-p.closeq:
   245  			break outer
   246  		case m = <-p.sendq:
   247  		}
   248  
   249  		if err := p.p.SendMsg(m); err != nil {
   250  			m.Free()
   251  			break
   252  		}
   253  	}
   254  	p.close()
   255  }
   256  
   257  func (p *pipe) receiver() {
   258  	s := p.s
   259  outer:
   260  	for {
   261  		m := p.p.RecvMsg()
   262  		if m == nil {
   263  			break
   264  		}
   265  
   266  		if len(m.Body) < 4 ||
   267  			m.Body[0] != 0 || m.Body[1] != 0 || m.Body[2] != 0 ||
   268  			int(m.Body[3]) >= s.ttl {
   269  			m.Free()
   270  			continue
   271  		}
   272  		m.Header = m.Body[:4]
   273  		m.Body = m.Body[4:]
   274  		m.Header[3]++
   275  
   276  		userm := m.Dup()
   277  		s.Lock()
   278  		for _, p2 := range s.pipes {
   279  			if p2 == p {
   280  				continue
   281  			}
   282  
   283  			m2 := m.Dup()
   284  			select {
   285  			case p2.sendq <- m2:
   286  			default:
   287  				m2.Free()
   288  			}
   289  		}
   290  		s.Unlock()
   291  		m.Free()
   292  
   293  		select {
   294  		case s.recvq <- userm:
   295  		case <-p.closeq:
   296  			userm.Free()
   297  			break outer
   298  		case <-s.closeq:
   299  			userm.Free()
   300  			break outer
   301  		}
   302  	}
   303  	p.close()
   304  }
   305  
   306  func (p *pipe) close() {
   307  	_ = p.p.Close()
   308  }
   309  
   310  // NewProtocol returns a new protocol implementation.
   311  func NewProtocol() protocol.Protocol {
   312  	s := &socket{
   313  		pipes:    make(map[uint32]*pipe),
   314  		closeq:   make(chan struct{}),
   315  		recvq:    make(chan *protocol.Message, defaultQLen),
   316  		sendQLen: defaultQLen,
   317  		recvQLen: defaultQLen,
   318  		ttl:      8,
   319  	}
   320  	return s
   321  }
   322  
   323  // NewSocket allocates a raw Socket using the BUS protocol.
   324  func NewSocket() (protocol.Socket, error) {
   325  	return protocol.MakeSocket(NewProtocol()), nil
   326  }