Coverage Report

Created: 2025-06-20 06:45

/src/mosquitto/lib/send_connect.c
Line
Count
Source (jump to first uncovered line)
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
int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session, const mosquitto_property *properties)
38
0
{
39
0
  struct mosquitto__packet *packet = NULL;
40
0
  uint32_t payloadlen;
41
0
  uint8_t will = 0;
42
0
  uint8_t byte;
43
0
  int rc;
44
0
  uint8_t version;
45
0
  char *clientid, *username, *password;
46
0
  uint32_t headerlen;
47
0
  uint32_t proplen = 0, varbytes;
48
0
  mosquitto_property *local_props = NULL;
49
0
  uint16_t receive_maximum;
50
51
0
  assert(mosq);
52
53
0
  if(mosq->protocol == mosq_p_mqtt31 && !mosq->id) return MOSQ_ERR_PROTOCOL;
54
55
0
#if defined(WITH_BROKER) && defined(WITH_BRIDGE)
56
0
  if(mosq->bridge){
57
0
    clientid = mosq->bridge->remote_clientid;
58
0
    username = mosq->bridge->remote_username;
59
0
    password = mosq->bridge->remote_password;
60
0
  }else{
61
0
    clientid = mosq->id;
62
0
    username = mosq->username;
63
0
    password = mosq->password;
64
0
  }
65
#else
66
  clientid = mosq->id;
67
  username = mosq->username;
68
  password = mosq->password;
69
#endif
70
71
0
  if(mosq->protocol == mosq_p_mqtt5){
72
    /* Generate properties from options */
73
0
    if(!mosquitto_property_read_int16(properties, MQTT_PROP_RECEIVE_MAXIMUM, &receive_maximum, false)){
74
0
      rc = mosquitto_property_add_int16(&local_props, MQTT_PROP_RECEIVE_MAXIMUM, mosq->msgs_in.inflight_maximum);
75
0
      if(rc) return rc;
76
0
    }else{
77
0
      mosq->msgs_in.inflight_maximum = receive_maximum;
78
0
      mosq->msgs_in.inflight_quota = receive_maximum;
79
0
    }
80
81
0
    version = MQTT_PROTOCOL_V5;
82
0
    headerlen = 10;
83
0
    proplen = 0;
84
0
    proplen += mosquitto_property_get_length_all(properties);
85
0
    proplen += mosquitto_property_get_length_all(local_props);
86
0
    varbytes = mosquitto_varint_bytes(proplen);
87
0
    headerlen += proplen + varbytes;
88
0
  }else if(mosq->protocol == mosq_p_mqtt311){
89
0
    version = MQTT_PROTOCOL_V311;
90
0
    headerlen = 10;
91
0
  }else if(mosq->protocol == mosq_p_mqtt31){
92
0
    version = MQTT_PROTOCOL_V31;
93
0
    headerlen = 12;
94
0
  }else{
95
0
    return MOSQ_ERR_INVAL;
96
0
  }
97
98
0
  if(clientid){
99
0
    payloadlen = (uint32_t)(2U+strlen(clientid));
100
0
  }else{
101
0
    payloadlen = 2U;
102
0
  }
103
0
#ifdef WITH_BROKER
104
0
  if(mosq->will && (mosq->bridge == NULL || mosq->bridge->notifications_local_only == false)){
105
#else
106
  if(mosq->will){
107
#endif
108
0
    will = 1;
109
0
    assert(mosq->will->msg.topic);
110
111
0
    payloadlen += (uint32_t)(2+strlen(mosq->will->msg.topic) + 2+(uint32_t)mosq->will->msg.payloadlen);
112
0
    if(mosq->protocol == mosq_p_mqtt5){
113
0
      payloadlen += mosquitto_property_get_remaining_length(mosq->will->properties);
114
0
    }
115
0
  }
116
117
  /* After this check we can be sure that the username and password are
118
   * always valid for the current protocol, so there is no need to check
119
   * username before checking password. */
120
0
  if(mosq->protocol == mosq_p_mqtt31 || mosq->protocol == mosq_p_mqtt311){
121
0
    if(password != NULL && username == NULL){
122
0
      return MOSQ_ERR_INVAL;
123
0
    }
124
0
  }
125
126
0
  if(username){
127
0
    payloadlen += (uint32_t)(2+strlen(username));
128
0
  }
129
0
  if(password){
130
0
    payloadlen += (uint32_t)(2+strlen(password));
131
0
  }
132
133
0
  rc = packet__alloc(&packet, CMD_CONNECT, headerlen + payloadlen);
134
0
  if(rc){
135
0
    mosquitto_FREE(packet);
136
0
    return rc;
137
0
  }
138
139
  /* Variable header */
140
0
  if(version == MQTT_PROTOCOL_V31){
141
0
    packet__write_string(packet, PROTOCOL_NAME_v31, (uint16_t)strlen(PROTOCOL_NAME_v31));
142
0
  }else{
143
0
    packet__write_string(packet, PROTOCOL_NAME, (uint16_t)strlen(PROTOCOL_NAME));
144
0
  }
145
0
#if defined(WITH_BROKER) && defined(WITH_BRIDGE)
146
0
  if(mosq->bridge && mosq->bridge->protocol_version != mosq_p_mqtt5 && mosq->bridge->try_private && mosq->bridge->try_private_accepted){
147
0
    version |= 0x80;
148
0
  }else{
149
0
  }
150
0
#endif
151
0
  packet__write_byte(packet, version);
152
0
  byte = (uint8_t)((clean_session&0x1)<<1);
153
0
  if(will){
154
0
    byte = byte | (uint8_t)(((mosq->will->msg.qos&0x3)<<3) | ((will&0x1)<<2));
155
0
    if(mosq->retain_available){
156
0
      byte |= (uint8_t)((mosq->will->msg.retain&0x1)<<5);
157
0
    }
158
0
  }
159
0
  if(username){
160
0
    byte = byte | 0x1<<7;
161
0
  }
162
0
  if(mosq->password){
163
0
    byte = byte | 0x1<<6;
164
0
  }
165
0
  packet__write_byte(packet, byte);
166
0
  packet__write_uint16(packet, keepalive);
167
168
0
  if(mosq->protocol == mosq_p_mqtt5){
169
    /* Write properties */
170
0
    packet__write_varint(packet, proplen);
171
0
    property__write_all(packet, properties, false);
172
0
    property__write_all(packet, local_props, false);
173
0
  }
174
0
  mosquitto_property_free_all(&local_props);
175
176
  /* Payload */
177
0
  if(clientid){
178
0
    packet__write_string(packet, clientid, (uint16_t)strlen(clientid));
179
0
  }else{
180
0
    packet__write_uint16(packet, 0);
181
0
  }
182
0
  if(will){
183
0
    if(mosq->protocol == mosq_p_mqtt5){
184
      /* Write will properties */
185
0
      property__write_all(packet, mosq->will->properties, true);
186
0
    }
187
0
    packet__write_string(packet, mosq->will->msg.topic, (uint16_t)strlen(mosq->will->msg.topic));
188
0
    packet__write_string(packet, (const char *)mosq->will->msg.payload, (uint16_t)mosq->will->msg.payloadlen);
189
0
  }
190
191
0
  if(username){
192
0
    packet__write_string(packet, username, (uint16_t)strlen(username));
193
0
  }
194
0
  if(password){
195
0
    packet__write_string(packet, password, (uint16_t)strlen(password));
196
0
  }
197
198
0
  mosq->keepalive = keepalive;
199
0
#ifdef WITH_BROKER
200
0
# ifdef WITH_BRIDGE
201
0
  log__printf(mosq, MOSQ_LOG_DEBUG, "Bridge %s sending CONNECT", SAFE_PRINT(clientid));
202
0
# endif
203
0
  metrics__int_inc(mosq_counter_mqtt_connect_sent, 1);
204
#else
205
  log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending CONNECT", SAFE_PRINT(clientid));
206
#endif
207
0
  return packet__queue(mosq, packet);
208
0
}
209