예제 #1
0
/**
 * Kick off a new publication, queue it or send it as appropriate.
 * @param pubclient the client to send the publication to
 * @param publish the publication data
 * @param qos the MQTT QoS to use
 * @param retained boolean - whether to set the MQTT retained flag
 * @param mm - pointer to the message to send
 * @return the completion code
 */
int MQTTProtocol_startOrQueuePublish(Clients* pubclient, Publish* publish, int qos, int retained, int priority, Messages** mm)
{
	int rc = TCPSOCKET_COMPLETE;
	int socket = pubclient->socket; /* used when MQTT_MP protocol is included */
	FUNC_ENTRY;

#if defined(MQTTMP)
	if (pubclient->protocol == PROTOCOL_MQTT_MP)
		socket = pubclient->actualSock;
#endif
	if (pubclient->connected && pubclient->good &&           /* client is connected and has no errors */
		Socket_noPendingWrites(socket) &&                    /* there aren't any previous packets still stacked up on the socket */
		queuedMsgsCount(pubclient) == 0 &&                   /* there are no messages ahead in the queue */
		pubclient->outboundMsgs->count < bstate->max_inflight_messages) /* the queue is not full */
	{
#if defined(MQTTS)
		if (pubclient->protocol == PROTOCOL_MQTTS && strlen(publish->topic) > 2 &&
				MQTTSProtocol_getRegisteredTopicId(pubclient, publish->topic) == 0)
		{
			if (pubclient->pendingRegistration == NULL)
				rc = MQTTSProtocol_startRegistration(pubclient, publish->topic);
			rc = MQTTProtocol_queuePublish(pubclient, publish, qos, retained, priority, mm);
		}
		else if (pubclient->protocol == PROTOCOL_MQTTS && qos > 0 && pubclient->outboundMsgs->count > 0)
		{
			/* can only have 1 qos 1/2 message in flight with MQTT-S */
			rc = MQTTProtocol_queuePublish(pubclient, publish, qos, retained, priority, mm);
		}
		else
		{
#endif
			rc = MQTTProtocol_startPublish(pubclient, publish, qos, retained, mm);
			/* We don't normally queue QoS 0 messages just send them straight through.  But in the case when none of the packet
			 * is written we need to queue it up.  If only part of the packet is written, then it is buffered by the socket module.
			 */
			if (qos == 0 && rc == TCPSOCKET_NOWORK)
				rc = MQTTProtocol_queuePublish(pubclient, publish, qos, retained, priority, mm);
#if defined(MQTTS)
		}
#endif
	}
	else if (qos != 0 || (pubclient->connected && pubclient->good))    /* only queue qos 0 if the client is connected in a good way */
		rc = MQTTProtocol_queuePublish(pubclient, publish, qos, retained, priority, mm);
	FUNC_EXIT_RC(rc);
	return rc;
}
예제 #2
0
int MQTTClient_publish(MQTTClient handle, const char* topicName, int payloadlen, void* payload,
							 int qos, int retained, MQTTClient_deliveryToken* deliveryToken)
{
	int rc = MQTTCLIENT_SUCCESS;
	MQTTClients* m = handle;
	Messages* msg = NULL;
	Publish* p = NULL;
	int blocked = 0;
	int msgid = 0;

	FUNC_ENTRY;
	Thread_lock_mutex(mqttclient_mutex);

	if (m == NULL || m->c == NULL)
		rc = MQTTCLIENT_FAILURE;
	else if (m->c->connected == 0)
		rc = MQTTCLIENT_DISCONNECTED;
	else if (!UTF8_validateString(topicName))
		rc = MQTTCLIENT_BAD_UTF8_STRING;
	if (rc != MQTTCLIENT_SUCCESS)
		goto exit;

	/* If outbound queue is full, block until it is not */
	while (m->c->outboundMsgs->count >= m->c->maxInflightMessages || 
         Socket_noPendingWrites(m->c->net.socket) == 0) /* wait until the socket is free of large packets being written */
	{
		if (blocked == 0)
		{
			blocked = 1;
			Log(TRACE_MIN, -1, "Blocking publish on queue full for client %s", m->c->clientID);
		}
		Thread_unlock_mutex(mqttclient_mutex);
		MQTTClient_yield();
		Thread_lock_mutex(mqttclient_mutex);
		if (m->c->connected == 0)
		{
			rc = MQTTCLIENT_FAILURE;
			goto exit;
		}
	}
	if (blocked == 1)
		Log(TRACE_MIN, -1, "Resuming publish now queue not full for client %s", m->c->clientID);
	if (qos > 0 && (msgid = MQTTProtocol_assignMsgId(m->c)) == 0)
	{	/* this should never happen as we've waited for spaces in the queue */
		rc = MQTTCLIENT_MAX_MESSAGES_INFLIGHT;
		goto exit;
	}

	p = malloc(sizeof(Publish));

	p->payload = payload;
	p->payloadlen = payloadlen;
	p->topic = (char*)topicName;
	p->msgId = msgid;

	rc = MQTTProtocol_startPublish(m->c, p, qos, retained, &msg);

	/* If the packet was partially written to the socket, wait for it to complete.
	 * However, if the client is disconnected during this time and qos is not 0, still return success, as
	 * the packet has already been written to persistence and assigned a message id so will
	 * be sent when the client next connects.
	 */
	if (rc == TCPSOCKET_INTERRUPTED)
	{
		while (m->c->connected == 1 && SocketBuffer_getWrite(m->c->net.socket))
		{
			Thread_unlock_mutex(mqttclient_mutex);
			MQTTClient_yield();
			Thread_lock_mutex(mqttclient_mutex);
		}
		rc = (qos > 0 || m->c->connected == 1) ? MQTTCLIENT_SUCCESS : MQTTCLIENT_FAILURE;
	}

	if (deliveryToken && qos > 0)
		*deliveryToken = msg->msgid;

	free(p);

	if (rc == SOCKET_ERROR)
	{
		Thread_unlock_mutex(mqttclient_mutex);
		MQTTClient_disconnect_internal(handle, 0);
		Thread_lock_mutex(mqttclient_mutex);
		/* Return success for qos > 0 as the send will be retried automatically */
		rc = (qos > 0) ? MQTTCLIENT_SUCCESS : MQTTCLIENT_FAILURE;
	}

exit:
	Thread_unlock_mutex(mqttclient_mutex);
	FUNC_EXIT_RC(rc);
	return rc;
}