Coverage Report

Created: 2025-07-04 06:47

/src/libzmq/src/null_mechanism.cpp
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: MPL-2.0 */
2
3
#include "precompiled.hpp"
4
5
#include <stddef.h>
6
#include <string.h>
7
#include <stdlib.h>
8
9
#include "err.hpp"
10
#include "msg.hpp"
11
#include "session_base.hpp"
12
#include "null_mechanism.hpp"
13
14
const char error_command_name[] = "\5ERROR";
15
const size_t error_command_name_len = sizeof (error_command_name) - 1;
16
const size_t error_reason_len_size = 1;
17
18
const char ready_command_name[] = "\5READY";
19
const size_t ready_command_name_len = sizeof (ready_command_name) - 1;
20
21
zmq::null_mechanism_t::null_mechanism_t (session_base_t *session_,
22
                                         const std::string &peer_address_,
23
                                         const options_t &options_) :
24
0
    mechanism_base_t (session_, options_),
25
0
    zap_client_t (session_, peer_address_, options_),
26
0
    _ready_command_sent (false),
27
0
    _error_command_sent (false),
28
0
    _ready_command_received (false),
29
0
    _error_command_received (false),
30
0
    _zap_request_sent (false),
31
0
    _zap_reply_received (false)
32
0
{
33
0
}
Unexecuted instantiation: zmq::null_mechanism_t::null_mechanism_t(zmq::session_base_t*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, zmq::options_t const&)
Unexecuted instantiation: zmq::null_mechanism_t::null_mechanism_t(zmq::session_base_t*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, zmq::options_t const&)
34
35
zmq::null_mechanism_t::~null_mechanism_t ()
36
0
{
37
0
}
38
39
int zmq::null_mechanism_t::next_handshake_command (msg_t *msg_)
40
0
{
41
0
    if (_ready_command_sent || _error_command_sent) {
42
0
        errno = EAGAIN;
43
0
        return -1;
44
0
    }
45
46
0
    if (zap_required () && !_zap_reply_received) {
47
0
        if (_zap_request_sent) {
48
0
            errno = EAGAIN;
49
0
            return -1;
50
0
        }
51
        //  Given this is a backward-incompatible change, it's behind a socket
52
        //  option disabled by default.
53
0
        int rc = session->zap_connect ();
54
0
        if (rc == -1 && options.zap_enforce_domain) {
55
0
            session->get_socket ()->event_handshake_failed_no_detail (
56
0
              session->get_endpoint (), EFAULT);
57
0
            return -1;
58
0
        }
59
0
        if (rc == 0) {
60
0
            send_zap_request ();
61
0
            _zap_request_sent = true;
62
63
            //  TODO actually, it is quite unlikely that we can read the ZAP
64
            //  reply already, but removing this has some strange side-effect
65
            //  (probably because the pipe's in_active flag is true until a read
66
            //  is attempted)
67
0
            rc = receive_and_process_zap_reply ();
68
0
            if (rc != 0)
69
0
                return -1;
70
71
0
            _zap_reply_received = true;
72
0
        }
73
0
    }
74
75
0
    if (_zap_reply_received && status_code != "200") {
76
0
        _error_command_sent = true;
77
0
        if (status_code != "300") {
78
0
            const size_t status_code_len = 3;
79
0
            const int rc = msg_->init_size (
80
0
              error_command_name_len + error_reason_len_size + status_code_len);
81
0
            zmq_assert (rc == 0);
82
0
            unsigned char *msg_data =
83
0
              static_cast<unsigned char *> (msg_->data ());
84
0
            memcpy (msg_data, error_command_name, error_command_name_len);
85
0
            msg_data += error_command_name_len;
86
0
            *msg_data = status_code_len;
87
0
            msg_data += error_reason_len_size;
88
0
            memcpy (msg_data, status_code.c_str (), status_code_len);
89
0
            return 0;
90
0
        }
91
0
        errno = EAGAIN;
92
0
        return -1;
93
0
    }
94
95
0
    make_command_with_basic_properties (msg_, ready_command_name,
96
0
                                        ready_command_name_len);
97
98
0
    _ready_command_sent = true;
99
100
0
    return 0;
101
0
}
102
103
int zmq::null_mechanism_t::process_handshake_command (msg_t *msg_)
104
0
{
105
0
    if (_ready_command_received || _error_command_received) {
106
0
        session->get_socket ()->event_handshake_failed_protocol (
107
0
          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
108
0
        errno = EPROTO;
109
0
        return -1;
110
0
    }
111
112
0
    const unsigned char *cmd_data =
113
0
      static_cast<unsigned char *> (msg_->data ());
114
0
    const size_t data_size = msg_->size ();
115
116
0
    int rc = 0;
117
0
    if (data_size >= ready_command_name_len
118
0
        && !memcmp (cmd_data, ready_command_name, ready_command_name_len))
119
0
        rc = process_ready_command (cmd_data, data_size);
120
0
    else if (data_size >= error_command_name_len
121
0
             && !memcmp (cmd_data, error_command_name, error_command_name_len))
122
0
        rc = process_error_command (cmd_data, data_size);
123
0
    else {
124
0
        session->get_socket ()->event_handshake_failed_protocol (
125
0
          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
126
0
        errno = EPROTO;
127
0
        rc = -1;
128
0
    }
129
130
0
    if (rc == 0) {
131
0
        rc = msg_->close ();
132
0
        errno_assert (rc == 0);
133
0
        rc = msg_->init ();
134
0
        errno_assert (rc == 0);
135
0
    }
136
0
    return rc;
137
0
}
138
139
int zmq::null_mechanism_t::process_ready_command (
140
  const unsigned char *cmd_data_, size_t data_size_)
141
0
{
142
0
    _ready_command_received = true;
143
0
    return parse_metadata (cmd_data_ + ready_command_name_len,
144
0
                           data_size_ - ready_command_name_len);
145
0
}
146
147
int zmq::null_mechanism_t::process_error_command (
148
  const unsigned char *cmd_data_, size_t data_size_)
149
0
{
150
0
    const size_t fixed_prefix_size =
151
0
      error_command_name_len + error_reason_len_size;
152
0
    if (data_size_ < fixed_prefix_size) {
153
0
        session->get_socket ()->event_handshake_failed_protocol (
154
0
          session->get_endpoint (),
155
0
          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR);
156
157
0
        errno = EPROTO;
158
0
        return -1;
159
0
    }
160
0
    const size_t error_reason_len =
161
0
      static_cast<size_t> (cmd_data_[error_command_name_len]);
162
0
    if (error_reason_len > data_size_ - fixed_prefix_size) {
163
0
        session->get_socket ()->event_handshake_failed_protocol (
164
0
          session->get_endpoint (),
165
0
          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR);
166
167
0
        errno = EPROTO;
168
0
        return -1;
169
0
    }
170
0
    const char *error_reason =
171
0
      reinterpret_cast<const char *> (cmd_data_) + fixed_prefix_size;
172
0
    handle_error_reason (error_reason, error_reason_len);
173
0
    _error_command_received = true;
174
0
    return 0;
175
0
}
176
177
int zmq::null_mechanism_t::zap_msg_available ()
178
0
{
179
0
    if (_zap_reply_received) {
180
0
        errno = EFSM;
181
0
        return -1;
182
0
    }
183
0
    const int rc = receive_and_process_zap_reply ();
184
0
    if (rc == 0)
185
0
        _zap_reply_received = true;
186
0
    return rc == -1 ? -1 : 0;
187
0
}
188
189
zmq::mechanism_t::status_t zmq::null_mechanism_t::status () const
190
0
{
191
0
    if (_ready_command_sent && _ready_command_received)
192
0
        return ready;
193
194
0
    const bool command_sent = _ready_command_sent || _error_command_sent;
195
0
    const bool command_received =
196
0
      _ready_command_received || _error_command_received;
197
0
    return command_sent && command_received ? error : handshaking;
198
0
}
199
200
void zmq::null_mechanism_t::send_zap_request ()
201
0
{
202
0
    zap_client_t::send_zap_request ("NULL", 4, NULL, NULL, 0);
203
0
}