// Recv receives a message. For AF_SP_RAW messages the header data will // be included at he start of the returned byte slice (otherwise it will // be stripped). At this time no flags are supported. func (s *Socket) Recv(flags int) ([]byte, error) { var b []byte var m *mangos.Message var err error if flags != 0 { return nil, errNoFlag } // Legacy nanomsg uses the opposite semantic for negative and // zero values than mangos. A bit unfortunate. switch { case s.rto > 0: s.sock.SetOption(mangos.OptionRecvDeadline, s.rto) case s.rto == 0: s.sock.SetOption(mangos.OptionRecvDeadline, -1) case s.rto < 0: s.sock.SetOption(mangos.OptionRecvDeadline, 0) } if m, err = s.sock.RecvMsg(); err != nil { return nil, err } if s.dom == AF_SP_RAW { b = make([]byte, 0, len(m.Body)+len(m.Header)) b = append(b, m.Header...) b = append(b, m.Body...) } else { b = make([]byte, 0, len(m.Body)) b = append(b, m.Body...) } m.Free() return b, nil }
func (x *bus) broadcast(m *mangos.Message, sender uint32) { x.Lock() for id, pe := range x.eps { if m != nil { if sender == id { continue } m = m.Dup() } select { case pe.q <- m: default: // No room on outbound queue, drop it. // Note that if we are passing on a linger/shutdown // notification and we can't deliver due to queue // full, it means we will wind up waiting the full // linger time in the lower sender. Its correct, if // suboptimal, behavior. if m != nil { m.Free() } } } x.Unlock() }
func (w *wsPipe) Send(m *mangos.Message) error { var buf []byte if len(m.Header) > 0 { buf = make([]byte, 0, len(m.Header)+len(m.Body)) buf = append(buf, m.Header...) buf = append(buf, m.Body...) } else { buf = m.Body } if err := websocket.Message.Send(w.ws, buf); err != nil { return err } m.Free() return nil }
func (x *surveyor) sender() { defer x.w.Done() sq := x.sock.SendChannel() cq := x.sock.CloseChannel() for { var m *mangos.Message select { case m = <-sq: case <-cq: return } x.Lock() for _, pe := range x.peers { m := m.Dup() select { case pe.q <- m: default: m.Free() } } x.Unlock() } }
func (x *star) broadcast(m *mangos.Message, sender *starEp) { x.Lock() for _, pe := range x.eps { if sender == pe { continue } if m != nil { m = m.Dup() } select { case pe.q <- m: default: // No room on outbound queue, drop it. if m != nil { m.Free() } } } x.Unlock() // Grab a local copy and send it up if we aren't originator if m != nil { if sender != nil { select { case x.sock.RecvChannel() <- m: case <-x.sock.CloseChannel(): m.Free() return default: // No room, so we just drop it. m.Free() } } else { // Not sending it up, so we need to release it. m.Free() } } }
func (r *rep) sender() { defer r.w.Done() sq := r.sock.SendChannel() cq := r.sock.CloseChannel() for { var m *mangos.Message select { case m = <-sq: case <-cq: return } // Lop off the 32-bit peer/pipe ID. If absent, drop. if len(m.Header) < 4 { m.Free() continue } id := binary.BigEndian.Uint32(m.Header) m.Header = m.Header[4:] r.Lock() pe := r.eps[id] r.Unlock() if pe == nil { m.Free() continue } select { case pe.q <- m: default: // If our queue is full, we have no choice but to // throw it on the floor. This shoudn't happen, // since each partner should be running synchronously. // Devices are a different situation, and this could // lead to lossy behavior there. Initiators will // resend if this happens. Devices need to have deep // enough queues and be fast enough to avoid this. m.Free() } } }
func (x *resp) sender() { // This is pretty easy because we have only one peer at a time. // If the peer goes away, we'll just drop the message on the floor. defer x.w.Done() cq := x.sock.CloseChannel() sq := x.sock.SendChannel() for { var m *mangos.Message select { case m = <-sq: case <-cq: return } // Lop off the 32-bit peer/pipe ID. If absent, drop. if len(m.Header) < 4 { m.Free() continue } id := binary.BigEndian.Uint32(m.Header) m.Header = m.Header[4:] x.Lock() peer := x.peers[id] x.Unlock() if peer == nil { m.Free() continue } // Put it on the outbound queue select { case peer.q <- m: default: // Backpressure, drop it. m.Free() } } }
func benchmarkPair(t *testing.B, url string, size int) { if strings.HasPrefix(url, "ipc://") && runtime.GOOS == "windows" { t.Skip("IPC not supported on Windows") return } srvopts := make(map[string]interface{}) cliopts := make(map[string]interface{}) if strings.HasPrefix(url, "wss://") || strings.HasPrefix(url, "tls+tcp://") { srvopts[mangos.OptionTLSConfig] = srvCfg cliopts[mangos.OptionTLSConfig] = cliCfg } finish := make(chan struct{}) ready := make(chan struct{}) srvsock, err := pair.NewSocket() if err != nil || srvsock == nil { t.Errorf("Failed creating server socket: %v", err) return } all.AddTransports(srvsock) defer srvsock.Close() clisock, err := pair.NewSocket() if err != nil || clisock == nil { t.Errorf("Failed creating client socket: %v", err) return } all.AddTransports(clisock) defer clisock.Close() go func() { var err error var m *mangos.Message if err = srvsock.ListenOptions(url, srvopts); err != nil { t.Errorf("Server listen failed: %v", err) return } close(ready) for i := 0; i < t.N; i++ { if m, err = srvsock.RecvMsg(); err != nil { t.Errorf("Error receiving %d: %v", i, err) return } m.Free() } close(finish) }() <-ready if err = clisock.DialOptions(url, cliopts); err != nil { t.Errorf("Client dial failed: %v", err) return } time.Sleep(700 * time.Millisecond) t.ResetTimer() for i := 0; i < t.N; i++ { msg := mangos.NewMessage(size) if err = clisock.SendMsg(msg); err != nil { t.Errorf("Client send failed: %v", err) return } } <-finish t.StopTimer() if size > 128 { t.SetBytes(int64(size)) } }