Ejemplo n.º 1
0
int MQTTSProtocol_handleSubscribes(void* pack, int sock, char* clientAddr, Clients* client)
{
	int rc = 0;
	MQTTS_Subscribe* sub = (MQTTS_Subscribe*)pack;
	int isnew;
	int topicId = 0;
	char* topicName = NULL , *preDefinedTopicName = NULL;

	FUNC_ENTRY;
	Log(LOG_PROTOCOL, 67, NULL, sock, clientAddr, client ? client->clientID : "",
		sub->msgId,
		(sub->flags.QoS == 3) ? -1: sub->flags.QoS,
		sub->flags.topicIdType);

	// NORMAL (topic name is in subscribe packet) or SHORT topic name
	if (sub->flags.topicIdType == MQTTS_TOPIC_TYPE_NORMAL || sub->flags.topicIdType == MQTTS_TOPIC_TYPE_SHORT)
	{
		topicName = sub->topicName;
		sub->topicName = NULL;
	}
	// Pre-defined topic
	else if (sub->flags.topicIdType == MQTTS_TOPIC_TYPE_PREDEFINED && client != NULL && sub->topicId != 0)
	{
		char *name = MQTTSProtocol_getPreRegisteredTopicName(client, sub->topicId) ;
		if (name) {
			preDefinedTopicName = MQTTSProtocol_replaceTopicNamePlaceholders(client , name ) ;
		}
		topicName = preDefinedTopicName ;
		topicId = sub->topicId;
	}

	// If topic name not found send SubAck with Rejected - Invalid topic ID
	if (topicName == NULL)
		rc = MQTTSPacket_send_subAck(client, sub, 0, sub->flags.QoS, MQTTS_RC_REJECTED_INVALID_TOPIC_ID);
	else
	{
		if (sub->flags.topicIdType == MQTTS_TOPIC_TYPE_NORMAL && !Topics_hasWildcards(topicName))
		{
			char* regTopicName = malloc(strlen(topicName)+1);
			strcpy(regTopicName, topicName);
			topicId = (MQTTSProtocol_registerTopic(client, regTopicName))->id;
		}

		isnew = SubscriptionEngines_subscribe(bstate->se, client->clientID,
				topicName, sub->flags.QoS, client->noLocal, (client->cleansession == 0), PRIORITY_NORMAL);

		if ( (rc = MQTTSPacket_send_subAck(client, sub, topicId, sub->flags.QoS, MQTTS_RC_ACCEPTED)) == 0)
			if ((client->noLocal == 0) || isnew)
				MQTTProtocol_processRetaineds(client, topicName,sub->flags.QoS, PRIORITY_NORMAL);
	}
	time( &(client->lastContact) );
	MQTTSPacket_free_packet(pack);
	if (preDefinedTopicName)
		free (preDefinedTopicName);
	FUNC_EXIT_RC(rc);
	return rc;
}
Ejemplo n.º 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;
}