Class: Protocol::ZMTP::Mechanism::Null

Inherits:
Object
  • Object
show all
Defined in:
lib/protocol/zmtp/mechanism/null.rb

Overview

NULL security mechanism — no encryption, no authentication.

Performs the ZMTP 3.1 greeting exchange and READY command handshake.

Constant Summary collapse

MECHANISM_NAME =
"NULL"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeNull

Returns a new instance of Null.



20
21
22
# File 'lib/protocol/zmtp/mechanism/null.rb', line 20

def initialize
  @metadata = nil
end

Instance Attribute Details

#metadataHash{String => String}

Extra READY properties an upper layer (e.g. an OMQ extension) wants this side to advertise. Mutated before #handshake!.

Returns:

  • (Hash{String => String})


17
18
19
# File 'lib/protocol/zmtp/mechanism/null.rb', line 17

def 
  @metadata
end

Instance Method Details

#encrypted?Boolean

Returns false — NULL does not encrypt frames.

Returns:

  • (Boolean)

    false — NULL does not encrypt frames



89
# File 'lib/protocol/zmtp/mechanism/null.rb', line 89

def encrypted? = false

#handshake!(io, as_server:, socket_type:, identity:, qos: 0, qos_hash: "") ⇒ Hash

Performs the full NULL handshake over io.

  1. Exchange 64-byte greetings

  2. Validate peer greeting (version, mechanism)

  3. Exchange READY commands (socket type + identity + any extras)

Parameters:

  • io (#read_exactly, #write, #flush)

    transport IO

  • as_server (Boolean)
  • socket_type (String)
  • identity (String)

Returns:

  • (Hash)

    { peer_socket_type:, peer_identity:, peer_qos:, peer_qos_hash:, peer_properties: }

Raises:



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/protocol/zmtp/mechanism/null.rb', line 37

def handshake!(io, as_server:, socket_type:, identity:, qos: 0, qos_hash: "")
  io.write(Codec::Greeting.encode(mechanism: MECHANISM_NAME, as_server: as_server))
  io.flush

  greeting_data = io.read_exactly(Codec::Greeting::SIZE)
  peer_greeting = Codec::Greeting.decode(greeting_data)

  unless peer_greeting[:mechanism] == MECHANISM_NAME
    raise Error, "unsupported mechanism: #{peer_greeting[:mechanism]}"
  end

  ready_cmd = Codec::Command.ready(
    socket_type:      socket_type,
    identity:         identity,
    qos:              qos,
    qos_hash:         qos_hash,
    metadata: @metadata,
  )
  io.write(ready_cmd.to_frame.to_wire)
  io.flush

  frame = Codec::Frame.read_from(io)
  unless frame.command?
    raise Error, "expected command frame, got data frame"
  end

  peer_cmd = Codec::Command.from_body(frame.body)
  unless peer_cmd.name == "READY"
    raise Error, "expected READY command, got #{peer_cmd.name}"
  end

  props            = peer_cmd.properties
  peer_socket_type = props["Socket-Type"]
  peer_identity    = props["Identity"] || ""
  peer_qos         = (props["X-QoS"] || "0").to_i
  peer_qos_hash    = props["X-QoS-Hash"] || ""

  unless peer_socket_type
    raise Error, "peer READY missing Socket-Type"
  end

  {
    peer_socket_type: peer_socket_type,
    peer_identity:    peer_identity,
    peer_qos:         peer_qos,
    peer_qos_hash:    peer_qos_hash,
    peer_properties:  props,
  }
end