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 <stdio.h>
20 #include <string.h>
21
22 #include "mosquitto_broker_internal.h"
23 #include "memory_mosq.h"
24 #include "mqtt_protocol.h"
25 #include "packet_mosq.h"
26 #include "send_mosq.h"
27 #include "util_mosq.h"
28
handle__connack(struct mosquitto_db * db,struct mosquitto * context)29 int handle__connack(struct mosquitto_db *db, struct mosquitto *context)
30 {
31 int rc;
32 uint8_t connect_acknowledge;
33 uint8_t reason_code;
34 int i;
35 char *notification_topic;
36 int notification_topic_len;
37 char notification_payload;
38 mosquitto_property *properties = NULL;
39
40 if(!context){
41 return MOSQ_ERR_INVAL;
42 }
43 log__printf(NULL, MOSQ_LOG_DEBUG, "Received CONNACK on connection %s.", context->id);
44 if(packet__read_byte(&context->in_packet, &connect_acknowledge)) return 1;
45 if(packet__read_byte(&context->in_packet, &reason_code)) return 1;
46
47 if(context->protocol == mosq_p_mqtt5){
48 rc = property__read_all(CMD_CONNACK, &context->in_packet, &properties);
49 if(rc) return rc;
50 mosquitto_property_free_all(&properties);
51 }
52 mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */
53
54 switch(reason_code){
55 case CONNACK_ACCEPTED:
56 if(context->bridge){
57 if(context->bridge->notifications){
58 notification_payload = '1';
59 if(context->bridge->notification_topic){
60 if(!context->bridge->notifications_local_only){
61 if(send__real_publish(context, mosquitto__mid_generate(context),
62 context->bridge->notification_topic, 1, ¬ification_payload, 1, true, 0, NULL, NULL, 0)){
63
64 return 1;
65 }
66 }
67 db__messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, ¬ification_payload, 1, 0, NULL);
68 }else{
69 notification_topic_len = strlen(context->bridge->remote_clientid)+strlen("$SYS/broker/connection//state");
70 notification_topic = mosquitto__malloc(sizeof(char)*(notification_topic_len+1));
71 if(!notification_topic) return MOSQ_ERR_NOMEM;
72
73 snprintf(notification_topic, notification_topic_len+1, "$SYS/broker/connection/%s/state", context->bridge->remote_clientid);
74 notification_payload = '1';
75 if(!context->bridge->notifications_local_only){
76 if(send__real_publish(context, mosquitto__mid_generate(context),
77 notification_topic, 1, ¬ification_payload, 1, true, 0, NULL, NULL, 0)){
78
79 mosquitto__free(notification_topic);
80 return 1;
81 }
82 }
83 db__messages_easy_queue(db, context, notification_topic, 1, 1, ¬ification_payload, 1, 0, NULL);
84 mosquitto__free(notification_topic);
85 }
86 }
87 for(i=0; i<context->bridge->topic_count; i++){
88 if(context->bridge->topics[i].direction == bd_in || context->bridge->topics[i].direction == bd_both){
89 if(send__subscribe(context, NULL, 1, &context->bridge->topics[i].remote_topic, context->bridge->topics[i].qos, NULL)){
90 return 1;
91 }
92 }else{
93 if(context->bridge->attempt_unsubscribe){
94 if(send__unsubscribe(context, NULL, 1, &context->bridge->topics[i].remote_topic, NULL)){
95 /* direction = inwards only. This means we should not be subscribed
96 * to the topic. It is possible that we used to be subscribed to
97 * this topic so unsubscribe. */
98 return 1;
99 }
100 }
101 }
102 }
103 for(i=0; i<context->bridge->topic_count; i++){
104 if(context->bridge->topics[i].direction == bd_out || context->bridge->topics[i].direction == bd_both){
105 sub__retain_queue(db, context,
106 context->bridge->topics[i].local_topic,
107 context->bridge->topics[i].qos, 0);
108 }
109 }
110 }
111 mosquitto__set_state(context, mosq_cs_active);
112 return MOSQ_ERR_SUCCESS;
113 case CONNACK_REFUSED_PROTOCOL_VERSION:
114 if(context->bridge){
115 context->bridge->try_private_accepted = false;
116 }
117 log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: unacceptable protocol version");
118 return 1;
119 case CONNACK_REFUSED_IDENTIFIER_REJECTED:
120 log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: identifier rejected");
121 return 1;
122 case CONNACK_REFUSED_SERVER_UNAVAILABLE:
123 log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: broker unavailable");
124 return 1;
125 case CONNACK_REFUSED_BAD_USERNAME_PASSWORD:
126 log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: broker unavailable");
127 return 1;
128 case CONNACK_REFUSED_NOT_AUTHORIZED:
129 log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: not authorised");
130 return 1;
131 default:
132 log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: unknown reason");
133 return 1;
134 }
135 return 1;
136 }
137
138