// readUserMsg is used to decode a userMsg from a TCP stream func (m *Memberlist) readUserMsg(bufConn io.Reader, dec *codec.Decoder) error { // Read the user message header var header userMsgHeader if err := dec.Decode(&header); err != nil { return err } // Read the user message into a buffer var userBuf []byte if header.UserMsgLen > 0 { userBuf = make([]byte, header.UserMsgLen) bytes, err := io.ReadAtLeast(bufConn, userBuf, header.UserMsgLen) if err == nil && bytes != header.UserMsgLen { err = fmt.Errorf( "Failed to read full user message (%d / %d)", bytes, header.UserMsgLen) } if err != nil { return err } d := m.config.Delegate if d != nil { d.NotifyMsg(userBuf) } } return nil }
// Deserialize is used to deserialize the time table // and restore the state func (t *TimeTable) Deserialize(dec *codec.Decoder) error { // Decode the table var table []TimeTableEntry if err := dec.Decode(&table); err != nil { return err } // Witness from oldest to newest n := len(table) for i := n - 1; i >= 0; i-- { t.Witness(table[i].Index, table[i].Time) } return nil }
// readRemoteState is used to read the remote state from a connection func (m *Memberlist) readRemoteState(bufConn io.Reader, dec *codec.Decoder) (bool, []pushNodeState, []byte, error) { // Read the push/pull header var header pushPullHeader if err := dec.Decode(&header); err != nil { return false, nil, nil, err } // Allocate space for the transfer remoteNodes := make([]pushNodeState, header.Nodes) // Try to decode all the states for i := 0; i < header.Nodes; i++ { if err := dec.Decode(&remoteNodes[i]); err != nil { return false, nil, nil, err } } // Read the remote user state into a buffer var userBuf []byte if header.UserStateLen > 0 { userBuf = make([]byte, header.UserStateLen) bytes, err := io.ReadAtLeast(bufConn, userBuf, header.UserStateLen) if err == nil && bytes != header.UserStateLen { err = fmt.Errorf( "Failed to read full user state (%d / %d)", bytes, header.UserStateLen) } if err != nil { return false, nil, nil, err } } // For proto versions < 2, there is no port provided. Mask old // behavior by using the configured port for idx := range remoteNodes { if m.ProtocolVersion() < 2 || remoteNodes[idx].Port == 0 { remoteNodes[idx].Port = uint16(m.config.BindPort) } } return header.Join, remoteNodes, userBuf, nil }
// handleCommand is used to decode and dispatch a single command. func (n *NetworkTransport) handleCommand(r *bufio.Reader, dec *codec.Decoder, enc *codec.Encoder) error { // Get the rpc type rpcType, err := r.ReadByte() if err != nil { return err } // Create the RPC object respCh := make(chan RPCResponse, 1) rpc := RPC{ RespChan: respCh, } // Decode the command isHeartbeat := false switch rpcType { case rpcAppendEntries: var req AppendEntriesRequest if err := dec.Decode(&req); err != nil { return err } rpc.Command = &req // Check if this is a heartbeat if req.Term != 0 && req.Leader != nil && req.PrevLogEntry == 0 && req.PrevLogTerm == 0 && len(req.Entries) == 0 && req.LeaderCommitIndex == 0 { isHeartbeat = true } case rpcRequestVote: var req RequestVoteRequest if err := dec.Decode(&req); err != nil { return err } rpc.Command = &req case rpcInstallSnapshot: var req InstallSnapshotRequest if err := dec.Decode(&req); err != nil { return err } rpc.Command = &req rpc.Reader = io.LimitReader(r, req.Size) default: return fmt.Errorf("unknown rpc type %d", rpcType) } // Check for heartbeat fast-path if isHeartbeat { n.heartbeatFnLock.Lock() fn := n.heartbeatFn n.heartbeatFnLock.Unlock() if fn != nil { fn(rpc) goto RESP } } // Dispatch the RPC select { case n.consumeCh <- rpc: case <-n.shutdownCh: return ErrTransportShutdown } // Wait for response RESP: select { case resp := <-respCh: // Send the error first respErr := "" if resp.Error != nil { respErr = resp.Error.Error() } if err := enc.Encode(respErr); err != nil { return err } // Send the response if err := enc.Encode(resp.Response); err != nil { return err } case <-n.shutdownCh: return ErrTransportShutdown } return nil }