Example #1
0
int config__get_dir_files(const char *include_dir, char ***files, int *file_count)
{
	char **l_files = NULL;
	int l_file_count = 0;
	char **files_tmp;
	int len;
	int i;

	DIR *dh;
	struct dirent *de;

	dh = opendir(include_dir);
	if(!dh){
		log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open include_dir '%s'.", include_dir);
		return 1;
	}
	while((de = readdir(dh)) != NULL){
		if(strlen(de->d_name) > 5){
			if(!strcmp(&de->d_name[strlen(de->d_name)-5], ".conf")){
				len = strlen(include_dir)+1+strlen(de->d_name)+1;

				l_file_count++;
				files_tmp = mosquitto__realloc(l_files, l_file_count*sizeof(char *));
				if(!files_tmp){
					for(i=0; i<l_file_count-1; i++){
						mosquitto__free(l_files[i]);
					}
					mosquitto__free(l_files);
					closedir(dh);
					return MOSQ_ERR_NOMEM;
				}
				l_files = files_tmp;

				l_files[l_file_count-1] = mosquitto__malloc(len+1);
				if(!l_files[l_file_count-1]){
					for(i=0; i<l_file_count-1; i++){
						mosquitto__free(l_files[i]);
					}
					mosquitto__free(l_files);
					closedir(dh);
					return MOSQ_ERR_NOMEM;
				}
				snprintf(l_files[l_file_count-1], len, "%s/%s", include_dir, de->d_name);
				l_files[l_file_count-1][len] = '\0';
			}
		}
	}
	closedir(dh);

	if(l_files){
		qsort(l_files, l_file_count, sizeof(char *), scmp_p);
	}
	*files = l_files;
	*file_count = l_file_count;

	return 0;
}
Example #2
0
int config__get_dir_files(const char *include_dir, char ***files, int *file_count)
{
	int len;
	int i;
	char **l_files = NULL;
	int l_file_count = 0;
	char **files_tmp;

	HANDLE fh;
	char dirpath[MAX_PATH];
	WIN32_FIND_DATA find_data;

	snprintf(dirpath, MAX_PATH, "%s\\*.conf", include_dir);
	fh = FindFirstFile(dirpath, &find_data);
	if(fh == INVALID_HANDLE_VALUE){
		log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open include_dir '%s'.", include_dir);
		return 1;
	}

	do{
		len = strlen(include_dir)+1+strlen(find_data.cFileName)+1;

		l_file_count++;
		files_tmp = mosquitto__realloc(l_files, l_file_count*sizeof(char *));
		if(!files_tmp){
			for(i=0; i<l_file_count-1; i++){
				mosquitto__free(l_files[i]);
			}
			mosquitto__free(l_files);
			FindClose(fh);
			return MOSQ_ERR_NOMEM;
		}
		l_files = files_tmp;

		l_files[l_file_count-1] = mosquitto__malloc(len+1);
		if(!l_files[l_file_count-1]){
			for(i=0; i<l_file_count-1; i++){
				mosquitto__free(l_files[i]);
			}
			mosquitto__free(l_files);
			FindClose(fh);
			return MOSQ_ERR_NOMEM;
		}
		snprintf(l_files[l_file_count-1], len, "%s/%s", include_dir, find_data.cFileName);
		l_files[l_file_count-1][len] = '\0';
	}while(FindNextFile(fh, &find_data));

	FindClose(fh);

	if(l_files){
		qsort(l_files, l_file_count, sizeof(char *), scmp_p);
	}
	*files = l_files;
	*file_count = l_file_count;

	return 0;
}
Example #3
0
int mosquitto_connect_srv(struct mosquitto *mosq, const char *host, int keepalive, const char *bind_address)
{
#ifdef WITH_SRV
	char *h;
	int rc;
	if(!mosq) return MOSQ_ERR_INVAL;

	rc = ares_init(&mosq->achan);
	if(rc != ARES_SUCCESS){
		return MOSQ_ERR_UNKNOWN;
	}

	if(!host){
		// get local domain
	}else{
#ifdef WITH_TLS
		if(mosq->tls_cafile || mosq->tls_capath || mosq->tls_psk){
			h = mosquitto__malloc(strlen(host) + strlen("_secure-mqtt._tcp.") + 1);
			if(!h) return MOSQ_ERR_NOMEM;
			sprintf(h, "_secure-mqtt._tcp.%s", host);
		}else{
#endif
			h = mosquitto__malloc(strlen(host) + strlen("_mqtt._tcp.") + 1);
			if(!h) return MOSQ_ERR_NOMEM;
			sprintf(h, "_mqtt._tcp.%s", host);
#ifdef WITH_TLS
		}
#endif
		ares_search(mosq->achan, h, ns_c_in, ns_t_srv, srv_callback, mosq);
		mosquitto__free(h);
	}

	pthread_mutex_lock(&mosq->state_mutex);
	mosq->state = mosq_cs_connect_srv;
	pthread_mutex_unlock(&mosq->state_mutex);

	mosq->keepalive = keepalive;

	return MOSQ_ERR_SUCCESS;

#else
	return MOSQ_ERR_NOT_SUPPORTED;
#endif
}
Example #4
0
int persist__chunk_client_msg_write_v5(FILE *db_fptr, struct P_client_msg *chunk)
{
	struct PF_header header;
	struct mosquitto__packet prop_packet;
	uint16_t id_len = chunk->F.id_len;
	uint32_t proplen = 0;
	int rc;

	memset(&prop_packet, 0, sizeof(struct mosquitto__packet));
	if(chunk->properties){
		proplen = property__get_length_all(chunk->properties);
		proplen += packet__varint_bytes(proplen);
	}

	chunk->F.mid = htons(chunk->F.mid);
	chunk->F.id_len = htons(chunk->F.id_len);

	header.chunk = htonl(DB_CHUNK_CLIENT_MSG);
	header.length = htonl(sizeof(struct PF_client_msg) + id_len + proplen);

	write_e(db_fptr, &header, sizeof(struct PF_header));
	write_e(db_fptr, &chunk->F, sizeof(struct PF_client_msg));
	write_e(db_fptr, chunk->client_id, id_len);
	if(chunk->properties){
		if(proplen > 0){
			prop_packet.remaining_length = proplen;
			prop_packet.packet_length = proplen;
			prop_packet.payload = mosquitto__malloc(proplen);
			if(!prop_packet.payload){
				return MOSQ_ERR_NOMEM;
			}
			rc = property__write_all(&prop_packet, chunk->properties, true);
			if(rc) return rc;

			write_e(db_fptr, prop_packet.payload, proplen);
			mosquitto__free(prop_packet.payload);
		}
	}

	return MOSQ_ERR_SUCCESS;
error:
	log__printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno));
	return 1;
}
Example #5
0
int handle__suback(struct mosquitto *mosq)
{
	uint16_t mid;
	uint8_t qos;
	int *granted_qos;
	int qos_count;
	int i = 0;
	int rc;

	assert(mosq);
#ifdef WITH_BROKER
	log__printf(NULL, MOSQ_LOG_DEBUG, "Received SUBACK from %s", mosq->id);
#else
	log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received SUBACK", mosq->id);
#endif
	rc = packet__read_uint16(&mosq->in_packet, &mid);
	if(rc) return rc;

	qos_count = mosq->in_packet.remaining_length - mosq->in_packet.pos;
	granted_qos = mosquitto__malloc(qos_count*sizeof(int));
	if(!granted_qos) return MOSQ_ERR_NOMEM;
	while(mosq->in_packet.pos < mosq->in_packet.remaining_length){
		rc = packet__read_byte(&mosq->in_packet, &qos);
		if(rc){
			mosquitto__free(granted_qos);
			return rc;
		}
		granted_qos[i] = (int)qos;
		i++;
	}
#ifndef WITH_BROKER
	pthread_mutex_lock(&mosq->callback_mutex);
	if(mosq->on_subscribe){
		mosq->in_callback = true;
		mosq->on_subscribe(mosq, mosq->userdata, mid, qos_count, granted_qos);
		mosq->in_callback = false;
	}
	pthread_mutex_unlock(&mosq->callback_mutex);
#endif
	mosquitto__free(granted_qos);

	return MOSQ_ERR_SUCCESS;
}
Example #6
0
int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup)
{
#ifdef WITH_BROKER
	size_t len;
#ifdef WITH_BRIDGE
	int i;
	struct mosquitto__bridge_topic *cur_topic;
	bool match;
	int rc;
	char *mapped_topic = NULL;
	char *topic_temp = NULL;
#endif
#endif
	assert(mosq);
	assert(topic);

#if defined(WITH_BROKER) && defined(WITH_WEBSOCKETS)
	if(mosq->sock == INVALID_SOCKET && !mosq->wsi) return MOSQ_ERR_NO_CONN;
#else
	if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN;
#endif

#ifdef WITH_BROKER
	if(mosq->listener && mosq->listener->mount_point){
		len = strlen(mosq->listener->mount_point);
		if(len < strlen(topic)){
			topic += len;
		}else{
			/* Invalid topic string. Should never happen, but silently swallow the message anyway. */
			return MOSQ_ERR_SUCCESS;
		}
	}
#ifdef WITH_BRIDGE
	if(mosq->bridge && mosq->bridge->topics && mosq->bridge->topic_remapping){
		for(i=0; i<mosq->bridge->topic_count; i++){
			cur_topic = &mosq->bridge->topics[i];
			if((cur_topic->direction == bd_both || cur_topic->direction == bd_out)
					&& (cur_topic->remote_prefix || cur_topic->local_prefix)){
				/* Topic mapping required on this topic if the message matches */

				rc = mosquitto_topic_matches_sub(cur_topic->local_topic, topic, &match);
				if(rc){
					return rc;
				}
				if(match){
					mapped_topic = mosquitto__strdup(topic);
					if(!mapped_topic) return MOSQ_ERR_NOMEM;
					if(cur_topic->local_prefix){
						/* This prefix needs removing. */
						if(!strncmp(cur_topic->local_prefix, mapped_topic, strlen(cur_topic->local_prefix))){
							topic_temp = mosquitto__strdup(mapped_topic+strlen(cur_topic->local_prefix));
							mosquitto__free(mapped_topic);
							if(!topic_temp){
								return MOSQ_ERR_NOMEM;
							}
							mapped_topic = topic_temp;
						}
					}

					if(cur_topic->remote_prefix){
						/* This prefix needs adding. */
						len = strlen(mapped_topic) + strlen(cur_topic->remote_prefix)+1;
						topic_temp = mosquitto__malloc(len+1);
						if(!topic_temp){
							mosquitto__free(mapped_topic);
							return MOSQ_ERR_NOMEM;
						}
						snprintf(topic_temp, len, "%s%s", cur_topic->remote_prefix, mapped_topic);
						topic_temp[len] = '\0';
						mosquitto__free(mapped_topic);
						mapped_topic = topic_temp;
					}
					log__printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBLISH to %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", mosq->id, dup, qos, retain, mid, mapped_topic, (long)payloadlen);
					G_PUB_BYTES_SENT_INC(payloadlen);
					rc =  send__real_publish(mosq, mid, mapped_topic, payloadlen, payload, qos, retain, dup);
					mosquitto__free(mapped_topic);
					return rc;
				}
			}
		}
	}
#endif
	log__printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBLISH to %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", mosq->id, dup, qos, retain, mid, topic, (long)payloadlen);
	G_PUB_BYTES_SENT_INC(payloadlen);
#else
	log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBLISH (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", mosq->id, dup, qos, retain, mid, topic, (long)payloadlen);
#endif

	return send__real_publish(mosq, mid, topic, payloadlen, payload, qos, retain, dup);
}
Example #7
0
static char *http__canonical_filename(
#ifndef LWS_LIBRARY_VERSION_NUMBER
		struct libwebsocket_context *context,
#endif
		struct libwebsocket *wsi,
		const char *in,
		const char *http_dir)
{
	size_t inlen, slen;
	char *filename, *filename_canonical;

	inlen = strlen(in);
	if(in[inlen-1] == '/'){
		slen = strlen(http_dir) + inlen + strlen("/index.html") + 2;
	}else{
		slen = strlen(http_dir) + inlen + 2;
	}
	filename = mosquitto__malloc(slen);
	if(!filename){
		libwebsockets_return_http_status(context, wsi, HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL);
		return NULL;
	}
	if(((char *)in)[inlen-1] == '/'){
		snprintf(filename, slen, "%s%sindex.html", http_dir, (char *)in);
	}else{
		snprintf(filename, slen, "%s%s", http_dir, (char *)in);
	}


	/* Get canonical path and check it is within our http_dir */
#ifdef WIN32
	filename_canonical = _fullpath(NULL, filename, 0);
	mosquitto__free(filename);
	if(!filename_canonical){
		libwebsockets_return_http_status(context, wsi, HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL);
		return NULL;
	}
#else
	filename_canonical = realpath(filename, NULL);
	mosquitto__free(filename);
	if(!filename_canonical){
		if(errno == EACCES){
			libwebsockets_return_http_status(context, wsi, HTTP_STATUS_FORBIDDEN, NULL);
		}else if(errno == EINVAL || errno == EIO || errno == ELOOP){
			libwebsockets_return_http_status(context, wsi, HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL);
		}else if(errno == ENAMETOOLONG){
			libwebsockets_return_http_status(context, wsi, HTTP_STATUS_REQ_URI_TOO_LONG, NULL);
		}else if(errno == ENOENT || errno == ENOTDIR){
			libwebsockets_return_http_status(context, wsi, HTTP_STATUS_NOT_FOUND, NULL);
		}
		return NULL;
	}
#endif
	if(strncmp(http_dir, filename_canonical, strlen(http_dir))){
		/* Requested file isn't within http_dir, deny access. */
		free(filename_canonical);
		libwebsockets_return_http_status(context, wsi, HTTP_STATUS_FORBIDDEN, NULL);
		return NULL;
	}

	return filename_canonical;
}
Example #8
0
static int callback_mqtt(struct libwebsocket_context *context,
#endif
		struct libwebsocket *wsi,
		enum libwebsocket_callback_reasons reason,
		void *user,
		void *in,
		size_t len)
{
	struct mosquitto_db *db;
	struct mosquitto *mosq = NULL;
	struct mosquitto__packet *packet;
	int count, i, j;
	const struct libwebsocket_protocols *p;
	struct libws_mqtt_data *u = (struct libws_mqtt_data *)user;
	size_t pos;
	uint8_t *buf;
	int rc;
	uint8_t byte;

	db = &int_db;

	switch (reason) {
		case LWS_CALLBACK_ESTABLISHED:
			mosq = context__init(db, WEBSOCKET_CLIENT);
			if(mosq){
				p = libwebsockets_get_protocol(wsi);
				for (i=0; i<db->config->listener_count; i++){
					if (db->config->listeners[i].protocol == mp_websockets) {
						for (j=0; db->config->listeners[i].ws_protocol[j].name; j++){
							if (p == &db->config->listeners[i].ws_protocol[j]){
								mosq->listener = &db->config->listeners[i];
								mosq->listener->client_count++;
							}
						}
					}
				}
				if(!mosq->listener){
					mosquitto__free(mosq);
					return -1;
				}
#if !defined(LWS_LIBRARY_VERSION_NUMBER)
				mosq->ws_context = context;
#endif
				mosq->wsi = wsi;
#ifdef WITH_TLS
				if(in){
					mosq->ssl = (SSL *)in;
					if(!mosq->listener->ssl_ctx){
						mosq->listener->ssl_ctx = SSL_get_SSL_CTX(mosq->ssl);
					}
				}
#endif
				u->mosq = mosq;
			}else{
				return -1;
			}
			easy_address(libwebsocket_get_socket_fd(wsi), mosq);
			if(!mosq->address){
				/* getpeername and inet_ntop failed and not a bridge */
				mosquitto__free(mosq);
				u->mosq = NULL;
				return -1;
			}
			if(mosq->listener->max_connections > 0 && mosq->listener->client_count > mosq->listener->max_connections){
				if(db->config->connection_messages == true){
					log__printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s denied: max_connections exceeded.", mosq->address);
				}
				mosquitto__free(mosq);
				u->mosq = NULL;
				return -1;
			}
			mosq->sock = libwebsocket_get_socket_fd(wsi);
			HASH_ADD(hh_sock, db->contexts_by_sock, sock, sizeof(mosq->sock), mosq);
			break;

		case LWS_CALLBACK_CLOSED:
			if(!u){
				return -1;
			}
			mosq = u->mosq;
			if(mosq){
				if(mosq->sock != INVALID_SOCKET){
					HASH_DELETE(hh_sock, db->contexts_by_sock, mosq);
					mosq->sock = INVALID_SOCKET;
					mosq->pollfd_index = -1;
				}
				mosq->wsi = NULL;
#ifdef WITH_TLS
				mosq->ssl = NULL;
#endif
				do_disconnect(db, mosq);
			}
			break;

		case LWS_CALLBACK_SERVER_WRITEABLE:
			if(!u){
				return -1;
			}
			mosq = u->mosq;
			if(!mosq){
				return -1;
			}

			db__message_write(db, mosq);

			if(mosq->out_packet && !mosq->current_out_packet){
				mosq->current_out_packet = mosq->out_packet;
				mosq->out_packet = mosq->out_packet->next;
				if(!mosq->out_packet){
					mosq->out_packet_last = NULL;
				}
			}

			if(mosq->current_out_packet && !lws_send_pipe_choked(mosq->wsi)){
				packet = mosq->current_out_packet;

				if(packet->pos == 0 && packet->to_process == packet->packet_length){
					/* First time this packet has been dealt with.
					 * libwebsockets requires that the payload has
					 * LWS_SEND_BUFFER_PRE_PADDING space available before the
					 * actual data and LWS_SEND_BUFFER_POST_PADDING afterwards.
					 * We've already made the payload big enough to allow this,
					 * but need to move it into position here. */
					memmove(&packet->payload[LWS_SEND_BUFFER_PRE_PADDING], packet->payload, packet->packet_length);
					packet->pos += LWS_SEND_BUFFER_PRE_PADDING;
				}
				count = libwebsocket_write(wsi, &packet->payload[packet->pos], packet->to_process, LWS_WRITE_BINARY);
				if(count < 0){
					if (mosq->state == mosq_cs_disconnect_ws || mosq->state == mosq_cs_disconnecting){
						return -1;
					}
					return 0;
				}
#ifdef WITH_SYS_TREE
				g_bytes_sent += count;
#endif
				packet->to_process -= count;
				packet->pos += count;
				if(packet->to_process > 0){
					if (mosq->state == mosq_cs_disconnect_ws || mosq->state == mosq_cs_disconnecting){
						return -1;
					}
					break;
				}

#ifdef WITH_SYS_TREE
				g_msgs_sent++;
				if(((packet->command)&0xF6) == PUBLISH){
					g_pub_msgs_sent++;
				}
#endif

				/* Free data and reset values */
				mosq->current_out_packet = mosq->out_packet;
				if(mosq->out_packet){
					mosq->out_packet = mosq->out_packet->next;
					if(!mosq->out_packet){
						mosq->out_packet_last = NULL;
					}
				}

				packet__cleanup(packet);
				mosquitto__free(packet);

				mosq->next_msg_out = mosquitto_time() + mosq->keepalive;
			}
			if (mosq->state == mosq_cs_disconnect_ws || mosq->state == mosq_cs_disconnecting){
				return -1;
			}
			if(mosq->current_out_packet){
				libwebsocket_callback_on_writable(mosq->ws_context, mosq->wsi);
			}
			break;

		case LWS_CALLBACK_RECEIVE:
			if(!u || !u->mosq){
				return -1;
			}
			mosq = u->mosq;
			pos = 0;
			buf = (uint8_t *)in;
			G_BYTES_RECEIVED_INC(len);
			while(pos < len){
				if(!mosq->in_packet.command){
					mosq->in_packet.command = buf[pos];
					pos++;
					/* Clients must send CONNECT as their first command. */
					if(mosq->state == mosq_cs_new && (mosq->in_packet.command&0xF0) != CONNECT){
						return -1;
					}
				}
				if(mosq->in_packet.remaining_count <= 0){
					do{
						if(pos == len){
							return 0;
						}
						byte = buf[pos];
						pos++;

						mosq->in_packet.remaining_count--;
						/* Max 4 bytes length for remaining length as defined by protocol.
						* Anything more likely means a broken/malicious client.
						*/
						if(mosq->in_packet.remaining_count < -4){
							return -1;
						}

						mosq->in_packet.remaining_length += (byte & 127) * mosq->in_packet.remaining_mult;
						mosq->in_packet.remaining_mult *= 128;
					}while((byte & 128) != 0);
					mosq->in_packet.remaining_count *= -1;

					if(mosq->in_packet.remaining_length > 0){
						mosq->in_packet.payload = mosquitto__malloc(mosq->in_packet.remaining_length*sizeof(uint8_t));
						if(!mosq->in_packet.payload){
							return -1;
						}
						mosq->in_packet.to_process = mosq->in_packet.remaining_length;
					}
				}
				if(mosq->in_packet.to_process>0){
					if(len - pos >= mosq->in_packet.to_process){
						memcpy(&mosq->in_packet.payload[mosq->in_packet.pos], &buf[pos], mosq->in_packet.to_process);
						mosq->in_packet.pos += mosq->in_packet.to_process;
						pos += mosq->in_packet.to_process;
						mosq->in_packet.to_process = 0;
					}else{
						memcpy(&mosq->in_packet.payload[mosq->in_packet.pos], &buf[pos], len-pos);
						mosq->in_packet.pos += len-pos;
						mosq->in_packet.to_process -= len-pos;
						return 0;
					}
				}
				/* All data for this packet is read. */
				mosq->in_packet.pos = 0;

#ifdef WITH_SYS_TREE
				G_MSGS_RECEIVED_INC(1);
				if(((mosq->in_packet.command)&0xF5) == PUBLISH){
					G_PUB_MSGS_RECEIVED_INC(1);
				}
#endif
				rc = handle__packet(db, mosq);

				/* Free data and reset values */
				packet__cleanup(&mosq->in_packet);

				mosq->last_msg_in = mosquitto_time();

				if(rc && (mosq->out_packet || mosq->current_out_packet)) {
					if(mosq->state != mosq_cs_disconnecting){
						mosq->state = mosq_cs_disconnect_ws;
					}
					libwebsocket_callback_on_writable(mosq->ws_context, mosq->wsi);
				} else if (rc) {
					do_disconnect(db, mosq);
					return -1;
				}
			}
			break;

		default:
			break;
	}

	return 0;
}
Example #9
0
int handle__unsubscribe(struct mosquitto_db *db, struct mosquitto *context)
{
	uint16_t mid;
	char *sub;
	int slen;
	int rc;
	uint8_t reason;
	int reason_code_count = 0;
	int reason_code_max;
	uint8_t *reason_codes = NULL, *reason_tmp;
	mosquitto_property *properties = NULL;

	if(!context) return MOSQ_ERR_INVAL;

	if(context->state != mosq_cs_connected){
		return MOSQ_ERR_PROTOCOL;
	}
	log__printf(NULL, MOSQ_LOG_DEBUG, "Received UNSUBSCRIBE from %s", context->id);

	if(context->protocol != mosq_p_mqtt31){
		if((context->in_packet.command&0x0F) != 0x02){
			return MOSQ_ERR_PROTOCOL;
		}
	}
	if(packet__read_uint16(&context->in_packet, &mid)) return 1;
	if(mid == 0) return MOSQ_ERR_PROTOCOL;

	if(context->protocol == mosq_p_mqtt5){
		rc = property__read_all(CMD_UNSUBSCRIBE, &context->in_packet, &properties);
		if(rc) return rc;
		/* Immediately free, we don't do anything with User Property at the moment */
		mosquitto_property_free_all(&properties);
	}

	if(context->protocol == mosq_p_mqtt311 || context->protocol == mosq_p_mqtt5){
		if(context->in_packet.pos == context->in_packet.remaining_length){
			/* No topic specified, protocol error. */
			return MOSQ_ERR_PROTOCOL;
		}
	}

	reason_code_max = 10;
	reason_codes = mosquitto__malloc(reason_code_max);
	if(!reason_codes){
		return MOSQ_ERR_NOMEM;
	}

	while(context->in_packet.pos < context->in_packet.remaining_length){
		sub = NULL;
		if(packet__read_string(&context->in_packet, &sub, &slen)){
			return 1;
		}

		if(!slen){
			log__printf(NULL, MOSQ_LOG_INFO,
					"Empty unsubscription string from %s, disconnecting.",
					context->id);
			mosquitto__free(sub);
			return 1;
		}
		if(mosquitto_sub_topic_check(sub)){
			log__printf(NULL, MOSQ_LOG_INFO,
					"Invalid unsubscription string from %s, disconnecting.",
					context->id);
			mosquitto__free(sub);
			return 1;
		}

		log__printf(NULL, MOSQ_LOG_DEBUG, "\t%s", sub);
		rc = sub__remove(db, context, sub, db->subs, &reason);
		log__printf(NULL, MOSQ_LOG_UNSUBSCRIBE, "%s %s", context->id, sub);
		mosquitto__free(sub);
		if(rc) return rc;

		reason_codes[reason_code_count] = reason;
		reason_code_count++;
		if(reason_code_count == reason_code_max){
			reason_tmp = mosquitto__realloc(reason_codes, reason_code_max*2);
			if(!reason_tmp){
				mosquitto__free(reason_codes);
				return MOSQ_ERR_NOMEM;
			}
			reason_codes = reason_tmp;
			reason_code_max *= 2;
		}
	}
#ifdef WITH_PERSISTENCE
	db->persistence_changes++;
#endif

	log__printf(NULL, MOSQ_LOG_DEBUG, "Sending UNSUBACK to %s", context->id);

	/* We don't use Reason String or User Property yet. */
	rc = send__unsuback(context, mid, reason_code_count, reason_codes, NULL);
	mosquitto__free(reason_codes);
	return rc;
}
Example #10
0
int bridge__connect(struct mosquitto_db *db, struct mosquitto *context)
{
	int rc, rc2;
	int i;
	char *notification_topic;
	int notification_topic_len;
	uint8_t notification_payload;

	if(!context || !context->bridge) return MOSQ_ERR_INVAL;

	context->state = mosq_cs_new;
	context->sock = INVALID_SOCKET;
	context->last_msg_in = mosquitto_time();
	context->next_msg_out = mosquitto_time() + context->bridge->keepalive;
	context->keepalive = context->bridge->keepalive;
	context->clean_session = context->bridge->clean_session;
	context->in_packet.payload = NULL;
	context->ping_t = 0;
	context->bridge->lazy_reconnect = false;
	bridge__packet_cleanup(context);
	db__message_reconnect_reset(db, context);

	if(context->clean_session){
		db__messages_delete(db, context);
	}

	/* Delete all local subscriptions even for clean_session==false. We don't
	 * remove any messages and the next loop carries out the resubscription
	 * anyway. This means any unwanted subs will be removed.
	 */
	sub__clean_session(db, context);

	for(i=0; i<context->bridge->topic_count; i++){
		if(context->bridge->topics[i].direction == bd_out || context->bridge->topics[i].direction == bd_both){
			log__printf(NULL, MOSQ_LOG_DEBUG, "Bridge %s doing local SUBSCRIBE on topic %s", context->id, context->bridge->topics[i].local_topic);
			if(sub__add(db, context, context->bridge->topics[i].local_topic, context->bridge->topics[i].qos, &db->subs)) return 1;
		}
	}

	if(context->bridge->notifications){
		if(context->bridge->notification_topic){
			if(!context->bridge->initial_notification_done){
				notification_payload = '0';
				db__messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, &notification_payload, 1);
				context->bridge->initial_notification_done = true;
			}

			if (!context->bridge->notifications_local_only) {
				notification_payload = '0';
				rc = will__set(context, context->bridge->notification_topic, 1, &notification_payload, 1, true);
				if(rc != MOSQ_ERR_SUCCESS){
					return rc;
				}
			}
		}else{
			notification_topic_len = strlen(context->bridge->remote_clientid)+strlen("$SYS/broker/connection//state");
			notification_topic = mosquitto__malloc(sizeof(char)*(notification_topic_len+1));
			if(!notification_topic) return MOSQ_ERR_NOMEM;

			snprintf(notification_topic, notification_topic_len+1, "$SYS/broker/connection/%s/state", context->bridge->remote_clientid);

			if(!context->bridge->initial_notification_done){
				notification_payload = '0';
				db__messages_easy_queue(db, context, notification_topic, 1, 1, &notification_payload, 1);
				context->bridge->initial_notification_done = true;
			}

			if (!context->bridge->notifications_local_only) {
				notification_payload = '0';
				rc = will__set(context, notification_topic, 1, &notification_payload, 1, true);
				mosquitto__free(notification_topic);
				if(rc != MOSQ_ERR_SUCCESS){
					return rc;
				}
			}
		}
	}

	log__printf(NULL, MOSQ_LOG_NOTICE, "Connecting bridge %s (%s:%d)", context->bridge->name, context->bridge->addresses[context->bridge->cur_address].address, context->bridge->addresses[context->bridge->cur_address].port);
	rc = net__socket_connect(context, context->bridge->addresses[context->bridge->cur_address].address, context->bridge->addresses[context->bridge->cur_address].port, NULL, false);
	if(rc > 0){
		if(rc == MOSQ_ERR_TLS){
			net__socket_close(db, context);
			return rc; /* Error already printed */
		}else if(rc == MOSQ_ERR_ERRNO){
			log__printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", strerror(errno));
		}else if(rc == MOSQ_ERR_EAI){
			log__printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", gai_strerror(errno));
		}

		return rc;
	}else if(rc == MOSQ_ERR_CONN_PENDING){
		context->state = mosq_cs_connect_pending;
	}

	HASH_ADD(hh_sock, db->contexts_by_sock, sock, sizeof(context->sock), context);

	rc2 = send__connect(context, context->keepalive, context->clean_session);
	if(rc2 == MOSQ_ERR_SUCCESS){
		return rc;
	}else if(rc2 == MOSQ_ERR_ERRNO && errno == ENOTCONN){
		return MOSQ_ERR_SUCCESS;
	}else{
		if(rc2 == MOSQ_ERR_TLS){
			return rc2; /* Error already printed */
		}else if(rc2 == MOSQ_ERR_ERRNO){
			log__printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", strerror(errno));
		}else if(rc2 == MOSQ_ERR_EAI){
			log__printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", gai_strerror(errno));
		}
		net__socket_close(db, context);
		return rc2;
	}
}
Example #11
0
int persist__chunk_message_store_write_v5(FILE *db_fptr, struct P_msg_store *chunk)
{
	struct PF_header header;
	uint32_t payloadlen = chunk->F.payloadlen;
	uint16_t source_id_len = chunk->F.source_id_len;
	uint16_t source_username_len = chunk->F.source_username_len;
	uint16_t topic_len = chunk->F.topic_len;
	uint32_t proplen = 0;
	struct mosquitto__packet prop_packet;
	int rc;

	memset(&prop_packet, 0, sizeof(struct mosquitto__packet));
	if(chunk->properties){
		proplen = property__get_length_all(chunk->properties);
		proplen += packet__varint_bytes(proplen);
	}

	chunk->F.payloadlen = htonl(chunk->F.payloadlen);
	chunk->F.source_mid = htons(chunk->F.source_mid);
	chunk->F.source_id_len = htons(chunk->F.source_id_len);
	chunk->F.source_username_len = htons(chunk->F.source_username_len);
	chunk->F.topic_len = htons(chunk->F.topic_len);
	chunk->F.source_port = htons(chunk->F.source_port);

	header.chunk = htonl(DB_CHUNK_MSG_STORE);
	header.length = htonl(sizeof(struct PF_msg_store) +
			topic_len + payloadlen +
			source_id_len + source_username_len + proplen);

	write_e(db_fptr, &header, sizeof(struct PF_header));
	write_e(db_fptr, &chunk->F, sizeof(struct PF_msg_store));
	if(source_id_len){
		write_e(db_fptr, chunk->source.id, source_id_len);
	}
	if(source_username_len){
		write_e(db_fptr, chunk->source.username, source_username_len);
	}
	write_e(db_fptr, chunk->topic, topic_len);
	if(payloadlen){
		write_e(db_fptr, UHPA_ACCESS(chunk->payload, payloadlen), (unsigned int)payloadlen);
	}
	if(chunk->properties){
		if(proplen > 0){
			prop_packet.remaining_length = proplen;
			prop_packet.packet_length = proplen;
			prop_packet.payload = mosquitto__malloc(proplen);
			if(!prop_packet.payload){
				return MOSQ_ERR_NOMEM;
			}
			rc = property__write_all(&prop_packet, chunk->properties, true);
			if(rc) return rc;

			write_e(db_fptr, prop_packet.payload, proplen);
			mosquitto__free(prop_packet.payload);
		}
	}

	return MOSQ_ERR_SUCCESS;
error:
	log__printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno));
	mosquitto__free(prop_packet.payload);
	return 1;
}
Example #12
0
int log__vprintf(int priority, const char *fmt, va_list va)
{
	char *s;
	char *st;
	int len;
#ifdef WIN32
	char *sp;
#endif
	const char *topic;
	int syslog_priority;
	time_t now = time(NULL);
	static time_t last_flush = 0;

	if((log_priorities & priority) && log_destinations != MQTT3_LOG_NONE){
		switch(priority){
			case MOSQ_LOG_SUBSCRIBE:
				topic = "$SYS/broker/log/M/subscribe";
#ifndef WIN32
				syslog_priority = LOG_NOTICE;
#else
				syslog_priority = EVENTLOG_INFORMATION_TYPE;
#endif
				break;
			case MOSQ_LOG_UNSUBSCRIBE:
				topic = "$SYS/broker/log/M/unsubscribe";
#ifndef WIN32
				syslog_priority = LOG_NOTICE;
#else
				syslog_priority = EVENTLOG_INFORMATION_TYPE;
#endif
				break;
			case MOSQ_LOG_DEBUG:
				topic = "$SYS/broker/log/D";
#ifndef WIN32
				syslog_priority = LOG_DEBUG;
#else
				syslog_priority = EVENTLOG_INFORMATION_TYPE;
#endif
				break;
			case MOSQ_LOG_ERR:
				topic = "$SYS/broker/log/E";
#ifndef WIN32
				syslog_priority = LOG_ERR;
#else
				syslog_priority = EVENTLOG_ERROR_TYPE;
#endif
				break;
			case MOSQ_LOG_WARNING:
				topic = "$SYS/broker/log/W";
#ifndef WIN32
				syslog_priority = LOG_WARNING;
#else
				syslog_priority = EVENTLOG_WARNING_TYPE;
#endif
				break;
			case MOSQ_LOG_NOTICE:
				topic = "$SYS/broker/log/N";
#ifndef WIN32
				syslog_priority = LOG_NOTICE;
#else
				syslog_priority = EVENTLOG_INFORMATION_TYPE;
#endif
				break;
			case MOSQ_LOG_INFO:
				topic = "$SYS/broker/log/I";
#ifndef WIN32
				syslog_priority = LOG_INFO;
#else
				syslog_priority = EVENTLOG_INFORMATION_TYPE;
#endif
				break;
#ifdef WITH_WEBSOCKETS
			case MOSQ_LOG_WEBSOCKETS:
				topic = "$SYS/broker/log/WS";
#ifndef WIN32
				syslog_priority = LOG_DEBUG;
#else
				syslog_priority = EVENTLOG_INFORMATION_TYPE;
#endif
				break;
#endif
			default:
				topic = "$SYS/broker/log/E";
#ifndef WIN32
				syslog_priority = LOG_ERR;
#else
				syslog_priority = EVENTLOG_ERROR_TYPE;
#endif
		}
		len = strlen(fmt) + 500;
		s = mosquitto__malloc(len*sizeof(char));
		if(!s) return MOSQ_ERR_NOMEM;

		vsnprintf(s, len, fmt, va);
		s[len-1] = '\0'; /* Ensure string is null terminated. */

		if(log_destinations & MQTT3_LOG_STDOUT){
			if(int_db.config && int_db.config->log_timestamp){
				fprintf(stdout, "%d: %s\n", (int)now, s);
			}else{
				fprintf(stdout, "%s\n", s);
			}
			fflush(stdout);
		}
		if(log_destinations & MQTT3_LOG_STDERR){
			if(int_db.config && int_db.config->log_timestamp){
				fprintf(stderr, "%d: %s\n", (int)now, s);
			}else{
				fprintf(stderr, "%s\n", s);
			}
			fflush(stderr);
		}
		if(log_destinations & MQTT3_LOG_FILE && int_db.config->log_fptr){
			if(int_db.config && int_db.config->log_timestamp){
				fprintf(int_db.config->log_fptr, "%d: %s\n", (int)now, s);
			}else{
				fprintf(int_db.config->log_fptr, "%s\n", s);
			}
			if(now - last_flush > 1){
				fflush(int_db.config->log_fptr);
				last_flush = now;
			}
		}
		if(log_destinations & MQTT3_LOG_SYSLOG){
#ifndef WIN32
			syslog(syslog_priority, "%s", s);
#else
			sp = (char *)s;
			ReportEvent(syslog_h, syslog_priority, 0, 0, NULL, 1, 0, &sp, NULL);
#endif
		}
		if(log_destinations & MQTT3_LOG_TOPIC && priority != MOSQ_LOG_DEBUG){
			if(int_db.config && int_db.config->log_timestamp){
				len += 30;
				st = mosquitto__malloc(len*sizeof(char));
				if(!st){
					mosquitto__free(s);
					return MOSQ_ERR_NOMEM;
				}
				snprintf(st, len, "%d: %s", (int)now, s);
				db__messages_easy_queue(&int_db, NULL, topic, 2, strlen(st), st, 0);
				mosquitto__free(st);
			}else{
				db__messages_easy_queue(&int_db, NULL, topic, 2, strlen(s), s, 0);
			}
		}
		mosquitto__free(s);
	}

	return MOSQ_ERR_SUCCESS;
}