Coverage Report

Created: 2025-08-26 06:06

/src/libzmq/src/plain_client.cpp
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: MPL-2.0 */
2
3
#include "precompiled.hpp"
4
#include "macros.hpp"
5
6
#include <string>
7
#include <limits.h>
8
9
#include "msg.hpp"
10
#include "err.hpp"
11
#include "plain_client.hpp"
12
#include "session_base.hpp"
13
#include "plain_common.hpp"
14
15
zmq::plain_client_t::plain_client_t (session_base_t *const session_,
16
                                     const options_t &options_) :
17
0
    mechanism_base_t (session_, options_), _state (sending_hello)
18
0
{
19
0
}
20
21
zmq::plain_client_t::~plain_client_t ()
22
0
{
23
0
}
24
25
int zmq::plain_client_t::next_handshake_command (msg_t *msg_)
26
0
{
27
0
    int rc = 0;
28
29
0
    switch (_state) {
30
0
        case sending_hello:
31
0
            produce_hello (msg_);
32
0
            _state = waiting_for_welcome;
33
0
            break;
34
0
        case sending_initiate:
35
0
            produce_initiate (msg_);
36
0
            _state = waiting_for_ready;
37
0
            break;
38
0
        default:
39
0
            errno = EAGAIN;
40
0
            rc = -1;
41
0
    }
42
0
    return rc;
43
0
}
44
45
int zmq::plain_client_t::process_handshake_command (msg_t *msg_)
46
0
{
47
0
    const unsigned char *cmd_data =
48
0
      static_cast<unsigned char *> (msg_->data ());
49
0
    const size_t data_size = msg_->size ();
50
51
0
    int rc = 0;
52
0
    if (data_size >= welcome_prefix_len
53
0
        && !memcmp (cmd_data, welcome_prefix, welcome_prefix_len))
54
0
        rc = process_welcome (cmd_data, data_size);
55
0
    else if (data_size >= ready_prefix_len
56
0
             && !memcmp (cmd_data, ready_prefix, ready_prefix_len))
57
0
        rc = process_ready (cmd_data, data_size);
58
0
    else if (data_size >= error_prefix_len
59
0
             && !memcmp (cmd_data, error_prefix, error_prefix_len))
60
0
        rc = process_error (cmd_data, data_size);
61
0
    else {
62
0
        session->get_socket ()->event_handshake_failed_protocol (
63
0
          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
64
0
        errno = EPROTO;
65
0
        rc = -1;
66
0
    }
67
68
0
    if (rc == 0) {
69
0
        rc = msg_->close ();
70
0
        errno_assert (rc == 0);
71
0
        rc = msg_->init ();
72
0
        errno_assert (rc == 0);
73
0
    }
74
75
0
    return rc;
76
0
}
77
78
zmq::mechanism_t::status_t zmq::plain_client_t::status () const
79
0
{
80
0
    switch (_state) {
81
0
        case ready:
82
0
            return mechanism_t::ready;
83
0
        case error_command_received:
84
0
            return mechanism_t::error;
85
0
        default:
86
0
            return mechanism_t::handshaking;
87
0
    }
88
0
}
89
90
void zmq::plain_client_t::produce_hello (msg_t *msg_) const
91
0
{
92
0
    const std::string username = options.plain_username;
93
0
    zmq_assert (username.length () <= UCHAR_MAX);
94
95
0
    const std::string password = options.plain_password;
96
0
    zmq_assert (password.length () <= UCHAR_MAX);
97
98
0
    const size_t command_size = hello_prefix_len + brief_len_size
99
0
                                + username.length () + brief_len_size
100
0
                                + password.length ();
101
102
0
    const int rc = msg_->init_size (command_size);
103
0
    errno_assert (rc == 0);
104
105
0
    unsigned char *ptr = static_cast<unsigned char *> (msg_->data ());
106
0
    memcpy (ptr, hello_prefix, hello_prefix_len);
107
0
    ptr += hello_prefix_len;
108
109
0
    *ptr++ = static_cast<unsigned char> (username.length ());
110
0
    memcpy (ptr, username.c_str (), username.length ());
111
0
    ptr += username.length ();
112
113
0
    *ptr++ = static_cast<unsigned char> (password.length ());
114
0
    memcpy (ptr, password.c_str (), password.length ());
115
0
}
116
117
int zmq::plain_client_t::process_welcome (const unsigned char *cmd_data_,
118
                                          size_t data_size_)
119
0
{
120
0
    LIBZMQ_UNUSED (cmd_data_);
121
122
0
    if (_state != waiting_for_welcome) {
123
0
        session->get_socket ()->event_handshake_failed_protocol (
124
0
          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
125
0
        errno = EPROTO;
126
0
        return -1;
127
0
    }
128
0
    if (data_size_ != welcome_prefix_len) {
129
0
        session->get_socket ()->event_handshake_failed_protocol (
130
0
          session->get_endpoint (),
131
0
          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME);
132
0
        errno = EPROTO;
133
0
        return -1;
134
0
    }
135
0
    _state = sending_initiate;
136
0
    return 0;
137
0
}
138
139
void zmq::plain_client_t::produce_initiate (msg_t *msg_) const
140
0
{
141
0
    make_command_with_basic_properties (msg_, initiate_prefix,
142
0
                                        initiate_prefix_len);
143
0
}
144
145
int zmq::plain_client_t::process_ready (const unsigned char *cmd_data_,
146
                                        size_t data_size_)
147
0
{
148
0
    if (_state != waiting_for_ready) {
149
0
        session->get_socket ()->event_handshake_failed_protocol (
150
0
          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
151
0
        errno = EPROTO;
152
0
        return -1;
153
0
    }
154
0
    const int rc = parse_metadata (cmd_data_ + ready_prefix_len,
155
0
                                   data_size_ - ready_prefix_len);
156
0
    if (rc == 0)
157
0
        _state = ready;
158
0
    else
159
0
        session->get_socket ()->event_handshake_failed_protocol (
160
0
          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA);
161
162
0
    return rc;
163
0
}
164
165
int zmq::plain_client_t::process_error (const unsigned char *cmd_data_,
166
                                        size_t data_size_)
167
0
{
168
0
    if (_state != waiting_for_welcome && _state != waiting_for_ready) {
169
0
        session->get_socket ()->event_handshake_failed_protocol (
170
0
          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
171
0
        errno = EPROTO;
172
0
        return -1;
173
0
    }
174
0
    const size_t start_of_error_reason = error_prefix_len + brief_len_size;
175
0
    if (data_size_ < start_of_error_reason) {
176
0
        session->get_socket ()->event_handshake_failed_protocol (
177
0
          session->get_endpoint (),
178
0
          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR);
179
0
        errno = EPROTO;
180
0
        return -1;
181
0
    }
182
0
    const size_t error_reason_len =
183
0
      static_cast<size_t> (cmd_data_[error_prefix_len]);
184
0
    if (error_reason_len > data_size_ - start_of_error_reason) {
185
0
        session->get_socket ()->event_handshake_failed_protocol (
186
0
          session->get_endpoint (),
187
0
          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR);
188
0
        errno = EPROTO;
189
0
        return -1;
190
0
    }
191
0
    const char *error_reason =
192
0
      reinterpret_cast<const char *> (cmd_data_) + start_of_error_reason;
193
0
    handle_error_reason (error_reason, error_reason_len);
194
0
    _state = error_command_received;
195
0
    return 0;
196
0
}