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

     1  // Copyright 2015 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 mangos
    16  
    17  // Device is used to create a forwarding loop between two sockets.  If the
    18  // same socket is listed (or either socket is nil), then a loopback device
    19  // is established instead.  Note that the single socket case is only valid
    20  // for protocols where the underlying protocol can peer for itself (e.g. PAIR,
    21  // or BUS, but not REQ/REP or PUB/SUB!)  Both sockets will be placed into RAW
    22  // mode.
    23  //
    24  // If the plumbing is successful, nil will be returned.  Two threads will be
    25  // established to forward messages in each direction.  If either socket returns
    26  // error on receive or send, the goroutine doing the forwarding will exit.
    27  // This means that closing either socket will generally cause the goroutines
    28  // to exit.  Apart from closing the socket(s), no further operations should be
    29  // performed against the socket.
    30  func Device(s1 Socket, s2 Socket) error {
    31  	// Is one of the sockets nil?
    32  	if s1 == nil {
    33  		s1 = s2
    34  	}
    35  	if s2 == nil {
    36  		s2 = s1
    37  	}
    38  	// At least one must be non-nil
    39  	if s1 == nil || s2 == nil {
    40  		return ErrClosed
    41  	}
    42  
    43  	p1 := s1.GetProtocol()
    44  	p2 := s2.GetProtocol()
    45  
    46  	if !ValidPeers(p1, p2) {
    47  		return ErrBadProto
    48  	}
    49  
    50  	if err := s1.SetOption(OptionRaw, true); err != nil {
    51  		return err
    52  	}
    53  	if err := s2.SetOption(OptionRaw, true); err != nil {
    54  		return err
    55  	}
    56  
    57  	go forwarder(s1, s2)
    58  	go forwarder(s2, s1)
    59  	return nil
    60  }
    61  
    62  // Forwarder takes messages from one socket, and sends them to the other.
    63  // The sockets must be of compatible types, and must be in Raw mode.
    64  func forwarder(fromSock Socket, toSock Socket) {
    65  	for {
    66  		m, err := fromSock.RecvMsg()
    67  		if err != nil {
    68  			// Probably closed socket, nothing else we can do.
    69  			return
    70  		}
    71  
    72  		err = toSock.SendMsg(m)
    73  		if err != nil {
    74  			return
    75  		}
    76  	}
    77  }