Coverage Report

Created: 2025-11-07 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mosquitto/lib/send_connect.c
Line
Count
Source
1
/*
2
Copyright (c) 2009-2021 Roger Light <roger@atchoo.org>
3
4
All rights reserved. This program and the accompanying materials
5
are made available under the terms of the Eclipse Public License 2.0
6
and Eclipse Distribution License v1.0 which accompany this distribution.
7
8
The Eclipse Public License is available at
9
   https://www.eclipse.org/legal/epl-2.0/
10
and the Eclipse Distribution License is available at
11
  http://www.eclipse.org/org/documents/edl-v10.php.
12
13
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
14
15
Contributors:
16
   Roger Light - initial implementation and documentation.
17
*/
18
19
#include "config.h"
20
21
#include <assert.h>
22
#include <string.h>
23
24
#ifdef WITH_BROKER
25
#  include "mosquitto_broker_internal.h"
26
#  include "sys_tree.h"
27
#endif
28
29
#include "logging_mosq.h"
30
#include "mosquitto.h"
31
#include "mosquitto_internal.h"
32
#include "mosquitto/mqtt_protocol.h"
33
#include "packet_mosq.h"
34
#include "property_mosq.h"
35
#include "send_mosq.h"
36
37
38
int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session, const mosquitto_property *properties)
39
0
{
40
0
  struct mosquitto__packet *packet = NULL;
41
0
  uint32_t payloadlen;
42
0
  uint8_t will = 0;
43
0
  uint8_t byte;
44
0
  int rc;
45
0
  uint8_t version;
46
0
  char *clientid, *username, *password;
47
0
  uint32_t headerlen;
48
0
  uint32_t proplen = 0, varbytes;
49
0
  mosquitto_property *local_props = NULL;
50
0
  uint16_t receive_maximum;
51
52
0
  assert(mosq);
53
54
0
  if(mosq->protocol == mosq_p_mqtt31 && !mosq->id){
55
0
    return MOSQ_ERR_PROTOCOL;
56
0
  }
57
58
0
#if defined(WITH_BROKER) && defined(WITH_BRIDGE)
59
0
  if(mosq->bridge){
60
0
    clientid = mosq->bridge->remote_clientid;
61
0
    username = mosq->bridge->remote_username;
62
0
    password = mosq->bridge->remote_password;
63
0
  }else{
64
0
    clientid = mosq->id;
65
0
    username = mosq->username;
66
0
    password = mosq->password;
67
0
  }
68
#else
69
  clientid = mosq->id;
70
  username = mosq->username;
71
  password = mosq->password;
72
#endif
73
74
0
  if(mosq->protocol == mosq_p_mqtt5){
75
    /* Generate properties from options */
76
0
    if(!mosquitto_property_read_int16(properties, MQTT_PROP_RECEIVE_MAXIMUM, &receive_maximum, false)){
77
0
      rc = mosquitto_property_add_int16(&local_props, MQTT_PROP_RECEIVE_MAXIMUM, mosq->msgs_in.inflight_maximum);
78
0
      if(rc){
79
0
        return rc;
80
0
      }
81
0
    }else{
82
0
      mosq->msgs_in.inflight_maximum = receive_maximum;
83
0
      mosq->msgs_in.inflight_quota = receive_maximum;
84
0
    }
85
86
0
    version = MQTT_PROTOCOL_V5;
87
0
    headerlen = 10;
88
0
    proplen = 0;
89
0
    proplen += mosquitto_property_get_length_all(properties);
90
0
    proplen += mosquitto_property_get_length_all(local_props);
91
0
    varbytes = mosquitto_varint_bytes(proplen);
92
0
    headerlen += proplen + varbytes;
93
0
  }else if(mosq->protocol == mosq_p_mqtt311){
94
0
    version = MQTT_PROTOCOL_V311;
95
0
    headerlen = 10;
96
0
  }else if(mosq->protocol == mosq_p_mqtt31){
97
0
    version = MQTT_PROTOCOL_V31;
98
0
    headerlen = 12;
99
0
  }else{
100
0
    return MOSQ_ERR_INVAL;
101
0
  }
102
103
0
  if(clientid){
104
0
    payloadlen = (uint32_t)(2U+strlen(clientid));
105
0
  }else{
106
0
    payloadlen = 2U;
107
0
  }
108
0
#ifdef WITH_BROKER
109
0
  if(mosq->will && (mosq->bridge == NULL || mosq->bridge->notifications_local_only == false)){
110
#else
111
  if(mosq->will){
112
#endif
113
0
    will = 1;
114
0
    assert(mosq->will->msg.topic);
115
116
0
    payloadlen += (uint32_t)(2+strlen(mosq->will->msg.topic) + 2+(uint32_t)mosq->will->msg.payloadlen);
117
0
    if(mosq->protocol == mosq_p_mqtt5){
118
0
      payloadlen += mosquitto_property_get_remaining_length(mosq->will->properties);
119
0
    }
120
0
  }
121
122
  /* After this check we can be sure that the username and password are
123
   * always valid for the current protocol, so there is no need to check
124
   * username before checking password. */
125
0
  if(mosq->protocol == mosq_p_mqtt31 || mosq->protocol == mosq_p_mqtt311){
126
0
    if(password != NULL && username == NULL){
127
0
      return MOSQ_ERR_INVAL;
128
0
    }
129
0
  }
130
131
0
  if(username){
132
0
    payloadlen += (uint32_t)(2+strlen(username));
133
0
  }
134
0
  if(password){
135
0
    payloadlen += (uint32_t)(2+strlen(password));
136
0
  }
137
138
0
  rc = packet__alloc(&packet, CMD_CONNECT, headerlen + payloadlen);
139
0
  if(rc){
140
0
    mosquitto_FREE(packet);
141
0
    return rc;
142
0
  }
143
144
  /* Variable header */
145
0
  if(version == MQTT_PROTOCOL_V31){
146
0
    packet__write_string(packet, PROTOCOL_NAME_v31, (uint16_t)strlen(PROTOCOL_NAME_v31));
147
0
  }else{
148
0
    packet__write_string(packet, PROTOCOL_NAME, (uint16_t)strlen(PROTOCOL_NAME));
149
0
  }
150
0
#if defined(WITH_BROKER) && defined(WITH_BRIDGE)
151
0
  if(mosq->bridge && mosq->bridge->protocol_version != mosq_p_mqtt5 && mosq->bridge->try_private && mosq->bridge->try_private_accepted){
152
0
    version |= 0x80;
153
0
  }else{
154
0
  }
155
0
#endif
156
0
  packet__write_byte(packet, version);
157
0
  byte = (uint8_t)((clean_session&0x1)<<1);
158
0
  if(will){
159
0
    byte = byte | (uint8_t)(((mosq->will->msg.qos&0x3)<<3) | ((will&0x1)<<2));
160
0
    if(mosq->retain_available){
161
0
      byte |= (uint8_t)((mosq->will->msg.retain&0x1)<<5);
162
0
    }
163
0
  }
164
0
  if(username){
165
0
    byte = byte | 0x1<<7;
166
0
  }
167
0
  if(mosq->password){
168
0
    byte = byte | 0x1<<6;
169
0
  }
170
0
  packet__write_byte(packet, byte);
171
0
  packet__write_uint16(packet, keepalive);
172
173
0
  if(mosq->protocol == mosq_p_mqtt5){
174
    /* Write properties */
175
0
    packet__write_varint(packet, proplen);
176
0
    property__write_all(packet, properties, false);
177
0
    property__write_all(packet, local_props, false);
178
0
  }
179
0
  mosquitto_property_free_all(&local_props);
180
181
  /* Payload */
182
0
  if(clientid){
183
0
    packet__write_string(packet, clientid, (uint16_t)strlen(clientid));
184
0
  }else{
185
0
    packet__write_uint16(packet, 0);
186
0
  }
187
0
  if(will){
188
0
    if(mosq->protocol == mosq_p_mqtt5){
189
      /* Write will properties */
190
0
      property__write_all(packet, mosq->will->properties, true);
191
0
    }
192
0
    packet__write_string(packet, mosq->will->msg.topic, (uint16_t)strlen(mosq->will->msg.topic));
193
0
    packet__write_string(packet, (const char *)mosq->will->msg.payload, (uint16_t)mosq->will->msg.payloadlen);
194
0
  }
195
196
0
  if(username){
197
0
    packet__write_string(packet, username, (uint16_t)strlen(username));
198
0
  }
199
0
  if(password){
200
0
    packet__write_string(packet, password, (uint16_t)strlen(password));
201
0
  }
202
203
0
  mosq->keepalive = keepalive;
204
0
#ifdef WITH_BROKER
205
0
# ifdef WITH_BRIDGE
206
0
  log__printf(mosq, MOSQ_LOG_DEBUG, "Bridge %s sending CONNECT", SAFE_PRINT(clientid));
207
0
# endif
208
0
  metrics__int_inc(mosq_counter_mqtt_connect_sent, 1);
209
#else
210
  log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending CONNECT", SAFE_PRINT(clientid));
211
#endif
212
0
  return packet__queue(mosq, packet);
213
0
}
214