Exemple #1
0
/**
 * Process retained messages (when a client subscribes)
 * @param client the client to send the messages to
 * @param topic the topic to match
 * @param qos the QoS of the subscription
 */
void MQTTProtocol_processRetaineds(Clients* client, char* topic, int qos, int priority)
{
	List* rpl = NULL;
	ListElement* currp = NULL;
#if defined(QOS0_SEND_LIMIT)
	int qos0count = 0;
#endif

	FUNC_ENTRY;
	rpl = SubscriptionEngines_getRetained(bstate->se, topic);
	while (ListNextElement(rpl, &currp))
	{
		int curqos;
		Publish publish;
		Messages* p = NULL;
		RetainedPublications* rp = (RetainedPublications*)(currp->content);

		publish.payload = rp->payload;
		publish.payloadlen = rp->payloadlen;
		publish.topic = rp->topicName;
		curqos = (rp->qos < qos) ? rp->qos : qos;
#if defined(QOS0_SEND_LIMIT)
		if (curqos == 0)
			++qos0count;
		if (qos0count > bstate->max_inflight_messages) /* a somewhat arbitrary criterion */
		{
			if (MQTTProtocol_queuePublish(client, &publish, curqos, 1, priority, &p) == SOCKET_ERROR)
				break;
		}
		else
		{
#endif
			if (Protocol_startOrQueuePublish(client, &publish, curqos, 1, priority, &p) == SOCKET_ERROR)
				break;
#if defined(QOS0_SEND_LIMIT)
		}
#endif
	}
	ListFreeNoContent(rpl);
	FUNC_EXIT;
}
Exemple #2
0
/**
 * Originates a new publication - sends it to all clients subscribed.
 * @param publish pointer to a stucture which contains all the publication information
 * @param originator the originating client
 */
void Protocol_processPublication(Publish* publish, char* originator)
{
	Messages* stored = NULL; /* to avoid duplication of data where possible */
	List* clients;
	ListElement* current = NULL;
	int savedMsgId = publish->msgId;
	int clean_needed = 0;

	FUNC_ENTRY;
	
	if (Topics_hasWildcards(publish->topic))
	{
		Log(LOG_INFO, 12, NULL, publish->topic, originator);
		goto exit;
	}

	if ((strcmp(INTERNAL_CLIENTID, originator) != 0) && bstate->password_file && bstate->acl_file)
	{
		Clients* client = (Clients*)(TreeFindIndex(bstate->clients, originator, 1)->content);
		
		if (Users_authorise(client->user, publish->topic, ACL_WRITE) == false)
		{
			Log(LOG_AUDIT, 149, NULL, originator, publish->topic);
			goto exit;
		}
	}

	if (publish->header.bits.retain)
	{
		SubscriptionEngines_setRetained(bstate->se, publish->topic, publish->header.bits.qos, publish->payload, publish->payloadlen);
		if (bstate->persistence == 1 && bstate->autosave_on_changes == 1 && bstate->autosave_interval > 0
			&& bstate->se->retained_changes >= bstate->autosave_interval)
		{
			Log(LOG_INFO, 100, NULL, bstate->autosave_interval);
			SubscriptionEngines_save(bstate->se);
		}
	}

	clients = SubscriptionEngines_getSubscribers(bstate->se, publish->topic, originator);
	if (strncmp(publish->topic, "$SYS/client/", 12) == 0)
	{ /* default subscription for a client */
		Node* node = TreeFindIndex(bstate->clients, &publish->topic[12], 1);
		if (node == NULL)
			node = TreeFind(bstate->disconnected_clients, &publish->topic[12]);
		if (node && node->content)
		{
			Subscriptions* rcs = malloc(sizeof(Subscriptions));
			rcs->clientName = &publish->topic[12];
			rcs->qos = 2;
			rcs->priority = PRIORITY_NORMAL;
			rcs->topicName = publish->topic;
			ListAppend(clients, rcs, sizeof(Subscriptions));
		}
	}
	current = NULL;
	while (ListNextElement(clients, &current))
	{
		Node* curnode = NULL;
		unsigned int qos = ((Subscriptions*)(current->content))->qos;
		int priority = ((Subscriptions*)(current->content))->priority;
		char* clientName = ((Subscriptions*)(current->content))->clientName;
		
		if (publish->header.bits.qos < qos) /* reduce qos if > subscribed qos */
			qos = publish->header.bits.qos;
			
		if ((curnode = TreeFindIndex(bstate->clients, clientName, 1)) == NULL)
			curnode = TreeFind(bstate->disconnected_clients, clientName);
#if defined(MQTTS)
		if (curnode == NULL && ((curnode = TreeFindIndex(bstate->mqtts_clients, clientName, 1)) == NULL))
			curnode = TreeFind(bstate->disconnected_mqtts_clients, clientName);
#endif

		if (curnode)
		{
			Clients* pubclient = (Clients*)(curnode->content);
			int retained = 0;
			Messages* saved = NULL;
			char* original_topic = publish->topic;
			
#if !defined(NO_BRIDGE)
			if (pubclient->outbound || pubclient->noLocal)
			{
				retained = publish->header.bits.retain; /* outbound and noLocal mean outward/inward bridge client,
																							so keep retained flag */
				if (pubclient->outbound)
				{
					Bridge_handleOutbound(pubclient, publish);
					if (publish->topic != original_topic)
					{ /* handleOutbound has changed the topic, so we musn't used the stored pub which
					        contains the original topic */
						saved = stored;
						stored = NULL;
					}
				}
			}
#endif
			if (Protocol_startOrQueuePublish(pubclient, publish, qos, retained, priority, &stored) == SOCKET_ERROR)
			{
				pubclient->good = pubclient->connected = 0; /* flag this client as needing to be cleaned up */
				clean_needed = 1;
			}
			if (publish->topic != original_topic)
			{
				stored = saved;  /* restore the stored pointer for the next loop iteration */
				free(publish->topic);
				publish->topic = original_topic;
			}
		}
	}
	publish->msgId = savedMsgId;
	/* INTERNAL_CLIENTID means that we are publishing data to the log,
			and we don't want to interfere with other close processing */
	if (clean_needed && strcmp(originator, INTERNAL_CLIENTID) != 0)
		MQTTProtocol_clean_clients(bstate->clients);
	ListFree(clients);
exit:
	FUNC_EXIT;
}