1 /*
2 Copyright (c) 2009-2020 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 v1.0
6 and Eclipse Distribution License v1.0 which accompany this distribution.
7 
8 The Eclipse Public License is available at
9    http://www.eclipse.org/legal/epl-v10.html
10 and the Eclipse Distribution License is available at
11   http://www.eclipse.org/org/documents/edl-v10.php.
12 
13 Contributors:
14    Roger Light - initial implementation and documentation.
15 */
16 
17 #include "config.h"
18 
19 #include <assert.h>
20 #include <stdio.h>
21 #include <string.h>
22 
23 #ifdef WITH_BROKER
24 #  include "mosquitto_broker_internal.h"
25 #  include "sys_tree.h"
26 #else
27 #  define G_PUB_BYTES_SENT_INC(A)
28 #endif
29 
30 #include "mosquitto.h"
31 #include "mosquitto_internal.h"
32 #include "logging_mosq.h"
33 #include "mqtt_protocol.h"
34 #include "memory_mosq.h"
35 #include "net_mosq.h"
36 #include "packet_mosq.h"
37 #include "property_mosq.h"
38 #include "send_mosq.h"
39 #include "time_mosq.h"
40 #include "util_mosq.h"
41 
send__pingreq(struct mosquitto * mosq)42 int send__pingreq(struct mosquitto *mosq)
43 {
44 	int rc;
45 	assert(mosq);
46 #ifdef WITH_BROKER
47 	log__printf(NULL, MOSQ_LOG_DEBUG, "Sending PINGREQ to %s", mosq->id);
48 #else
49 	log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PINGREQ", mosq->id);
50 #endif
51 	rc = send__simple_command(mosq, CMD_PINGREQ);
52 	if(rc == MOSQ_ERR_SUCCESS){
53 		mosq->ping_t = mosquitto_time();
54 	}
55 	return rc;
56 }
57 
send__pingresp(struct mosquitto * mosq)58 int send__pingresp(struct mosquitto *mosq)
59 {
60 #ifdef WITH_BROKER
61 	log__printf(NULL, MOSQ_LOG_DEBUG, "Sending PINGRESP to %s", mosq->id);
62 #else
63 	log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PINGRESP", mosq->id);
64 #endif
65 	return send__simple_command(mosq, CMD_PINGRESP);
66 }
67 
send__puback(struct mosquitto * mosq,uint16_t mid,uint8_t reason_code)68 int send__puback(struct mosquitto *mosq, uint16_t mid, uint8_t reason_code)
69 {
70 #ifdef WITH_BROKER
71 	log__printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBACK to %s (m%d, rc%d)", mosq->id, mid, reason_code);
72 #else
73 	log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBACK (m%d, rc%d)", mosq->id, mid, reason_code);
74 #endif
75 	util__increment_receive_quota(mosq);
76 	/* We don't use Reason String or User Property yet. */
77 	return send__command_with_mid(mosq, CMD_PUBACK, mid, false, reason_code, NULL);
78 }
79 
send__pubcomp(struct mosquitto * mosq,uint16_t mid)80 int send__pubcomp(struct mosquitto *mosq, uint16_t mid)
81 {
82 #ifdef WITH_BROKER
83 	log__printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBCOMP to %s (m%d)", mosq->id, mid);
84 #else
85 	log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBCOMP (m%d)", mosq->id, mid);
86 #endif
87 	util__increment_receive_quota(mosq);
88 	/* We don't use Reason String or User Property yet. */
89 	return send__command_with_mid(mosq, CMD_PUBCOMP, mid, false, 0, NULL);
90 }
91 
92 
send__pubrec(struct mosquitto * mosq,uint16_t mid,uint8_t reason_code)93 int send__pubrec(struct mosquitto *mosq, uint16_t mid, uint8_t reason_code)
94 {
95 #ifdef WITH_BROKER
96 	log__printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBREC to %s (m%d, rc%d)", mosq->id, mid, reason_code);
97 #else
98 	log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBREC (m%d, rc%d)", mosq->id, mid, reason_code);
99 #endif
100 	if(reason_code >= 0x80 && mosq->protocol == mosq_p_mqtt5){
101 		util__increment_receive_quota(mosq);
102 	}
103 	/* We don't use Reason String or User Property yet. */
104 	return send__command_with_mid(mosq, CMD_PUBREC, mid, false, reason_code, NULL);
105 }
106 
send__pubrel(struct mosquitto * mosq,uint16_t mid)107 int send__pubrel(struct mosquitto *mosq, uint16_t mid)
108 {
109 #ifdef WITH_BROKER
110 	log__printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBREL to %s (m%d)", mosq->id, mid);
111 #else
112 	log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBREL (m%d)", mosq->id, mid);
113 #endif
114 	/* We don't use Reason String or User Property yet. */
115 	return send__command_with_mid(mosq, CMD_PUBREL|2, mid, false, 0, NULL);
116 }
117 
118 /* For PUBACK, PUBCOMP, PUBREC, and PUBREL */
send__command_with_mid(struct mosquitto * mosq,uint8_t command,uint16_t mid,bool dup,uint8_t reason_code,const mosquitto_property * properties)119 int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup, uint8_t reason_code, const mosquitto_property *properties)
120 {
121 	struct mosquitto__packet *packet = NULL;
122 	int rc;
123 	int proplen, varbytes;
124 
125 	assert(mosq);
126 	packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet));
127 	if(!packet) return MOSQ_ERR_NOMEM;
128 
129 	packet->command = command;
130 	if(dup){
131 		packet->command |= 8;
132 	}
133 	packet->remaining_length = 2;
134 
135 	if(mosq->protocol == mosq_p_mqtt5){
136 		if(reason_code != 0 || properties){
137 			packet->remaining_length += 1;
138 		}
139 
140 		if(properties){
141 			proplen = property__get_length_all(properties);
142 			varbytes = packet__varint_bytes(proplen);
143 			packet->remaining_length += varbytes + proplen;
144 		}
145 	}
146 
147 	rc = packet__alloc(packet);
148 	if(rc){
149 		mosquitto__free(packet);
150 		return rc;
151 	}
152 
153 	packet__write_uint16(packet, mid);
154 
155 	if(mosq->protocol == mosq_p_mqtt5){
156 		if(reason_code != 0 || properties){
157 			packet__write_byte(packet, reason_code);
158 		}
159 		if(properties){
160 			property__write_all(packet, properties, true);
161 		}
162 	}
163 
164 	return packet__queue(mosq, packet);
165 }
166 
167 /* For DISCONNECT, PINGREQ and PINGRESP */
send__simple_command(struct mosquitto * mosq,uint8_t command)168 int send__simple_command(struct mosquitto *mosq, uint8_t command)
169 {
170 	struct mosquitto__packet *packet = NULL;
171 	int rc;
172 
173 	assert(mosq);
174 	packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet));
175 	if(!packet) return MOSQ_ERR_NOMEM;
176 
177 	packet->command = command;
178 	packet->remaining_length = 0;
179 
180 	rc = packet__alloc(packet);
181 	if(rc){
182 		mosquitto__free(packet);
183 		return rc;
184 	}
185 
186 	return packet__queue(mosq, packet);
187 }
188 
189