github.com/gdamore/mangos@v1.4.0/protocol/pair/pair.go (about)

     1  // Copyright 2018 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 pair implements the PAIR protocol.  This protocol is a 1:1
    16  // peering protocol.
    17  package pair
    18  
    19  import (
    20  	"sync"
    21  	"time"
    22  
    23  	"nanomsg.org/go-mangos"
    24  )
    25  
    26  type pair struct {
    27  	sock mangos.ProtocolSocket
    28  	peer *pairEp
    29  	raw  bool
    30  	w    mangos.Waiter
    31  	sync.Mutex
    32  }
    33  
    34  type pairEp struct {
    35  	ep mangos.Endpoint
    36  	cq chan struct{}
    37  }
    38  
    39  func (x *pair) Init(sock mangos.ProtocolSocket) {
    40  	x.sock = sock
    41  	x.w.Init()
    42  }
    43  
    44  func (x *pair) Shutdown(expire time.Time) {
    45  	x.w.WaitAbsTimeout(expire)
    46  }
    47  
    48  func (x *pair) sender(ep *pairEp) {
    49  
    50  	defer x.w.Done()
    51  	sq := x.sock.SendChannel()
    52  	cq := x.sock.CloseChannel()
    53  
    54  	// This is pretty easy because we have only one peer at a time.
    55  	// If the peer goes away, we'll just drop the message on the floor.
    56  	for {
    57  		select {
    58  		case m := <-sq:
    59  			if m == nil {
    60  				sq = x.sock.SendChannel()
    61  				continue
    62  			}
    63  			if ep.ep.SendMsg(m) != nil {
    64  				m.Free()
    65  				return
    66  			}
    67  		case <-ep.cq:
    68  			return
    69  		case <-cq:
    70  			return
    71  		}
    72  	}
    73  }
    74  
    75  func (x *pair) receiver(ep *pairEp) {
    76  
    77  	rq := x.sock.RecvChannel()
    78  	cq := x.sock.CloseChannel()
    79  
    80  	for {
    81  		m := ep.ep.RecvMsg()
    82  		if m == nil {
    83  			return
    84  		}
    85  
    86  		select {
    87  		case rq <- m:
    88  		case <-cq:
    89  			return
    90  		}
    91  	}
    92  }
    93  
    94  func (x *pair) AddEndpoint(ep mangos.Endpoint) {
    95  	peer := &pairEp{cq: make(chan struct{}), ep: ep}
    96  	x.Lock()
    97  	if x.peer != nil {
    98  		// We already have a connection, reject this one.
    99  		x.Unlock()
   100  		ep.Close()
   101  		return
   102  	}
   103  	x.peer = peer
   104  	x.Unlock()
   105  
   106  	x.w.Add()
   107  	go x.receiver(peer)
   108  	go x.sender(peer)
   109  }
   110  
   111  func (x *pair) RemoveEndpoint(ep mangos.Endpoint) {
   112  	x.Lock()
   113  	if peer := x.peer; peer != nil && peer.ep == ep {
   114  		x.peer = nil
   115  		close(peer.cq)
   116  	}
   117  	x.Unlock()
   118  }
   119  
   120  func (*pair) Number() uint16 {
   121  	return mangos.ProtoPair
   122  }
   123  
   124  func (*pair) Name() string {
   125  	return "pair"
   126  }
   127  
   128  func (*pair) PeerNumber() uint16 {
   129  	return mangos.ProtoPair
   130  }
   131  
   132  func (*pair) PeerName() string {
   133  	return "pair"
   134  }
   135  
   136  func (x *pair) SetOption(name string, v interface{}) error {
   137  	var ok bool
   138  	switch name {
   139  	case mangos.OptionRaw:
   140  		if x.raw, ok = v.(bool); !ok {
   141  			return mangos.ErrBadValue
   142  		}
   143  		return nil
   144  	default:
   145  		return mangos.ErrBadOption
   146  	}
   147  }
   148  
   149  func (x *pair) GetOption(name string) (interface{}, error) {
   150  	switch name {
   151  	case mangos.OptionRaw:
   152  		return x.raw, nil
   153  	default:
   154  		return nil, mangos.ErrBadOption
   155  	}
   156  }
   157  
   158  // NewSocket allocates a new Socket using the PAIR protocol.
   159  func NewSocket() (mangos.Socket, error) {
   160  	return mangos.MakeSocket(&pair{}), nil
   161  }