void MQTTClient_yield(void) { START_TIME_TYPE start = MQTTClient_start_clock(); unsigned long elapsed = 0L; unsigned long timeout = 100L; int rc = 0; FUNC_ENTRY; if (running) { MQTTClient_sleep(timeout); goto exit; } elapsed = MQTTClient_elapsed(start); do { int sock = -1; MQTTClient_cycle(&sock, (timeout > elapsed) ? timeout - elapsed : 0L, &rc); if (rc == SOCKET_ERROR && ListFindItem(handles, &sock, clientSockCompare)) { MQTTClients* m = (MQTTClient)(handles->current->content); if (m->c->connect_state != -2) MQTTClient_disconnect_internal(m, 0); } elapsed = MQTTClient_elapsed(start); } while (elapsed < timeout); exit: FUNC_EXIT; }
int MQTTClient_receive(MQTTClient handle, char** topicName, int* topicLen, MQTTClient_message** message, unsigned long timeout) { int rc = TCPSOCKET_COMPLETE; START_TIME_TYPE start = MQTTClient_start_clock(); unsigned long elapsed = 0L; MQTTClients* m = handle; FUNC_ENTRY; if (m == NULL || m->c == NULL) { rc = MQTTCLIENT_FAILURE; goto exit; } if (m->c->connected == 0) { rc = MQTTCLIENT_DISCONNECTED; goto exit; } *topicName = NULL; *message = NULL; /* if there is already a message waiting, don't hang around but still do some packet handling */ if (m->c->messageQueue->count > 0) timeout = 0L; elapsed = MQTTClient_elapsed(start); do { int sock = 0; MQTTClient_cycle(&sock, (timeout > elapsed) ? timeout - elapsed : 0L, &rc); if (rc == SOCKET_ERROR) { if (ListFindItem(handles, &sock, clientSockCompare) && /* find client corresponding to socket */ (MQTTClient)(handles->current->content) == handle) break; /* there was an error on the socket we are interested in */ } elapsed = MQTTClient_elapsed(start); } while (elapsed < timeout && m->c->messageQueue->count == 0); if (m->c->messageQueue->count > 0) rc = MQTTClient_deliverMessage(rc, m, topicName, topicLen, message); if (rc == SOCKET_ERROR) MQTTClient_disconnect_internal(handle, 0); exit: FUNC_EXIT_RC(rc); return rc; }
/* This is the thread function that handles the calling of callback functions if set */ thread_return_type WINAPI MQTTClient_run(void* n) { long timeout = 10L; /* first time in we have a small timeout. Gets things started more quickly */ FUNC_ENTRY; running = 1; run_id = Thread_getid(); Thread_lock_mutex(mqttclient_mutex); while (!tostop) { int rc = SOCKET_ERROR; int sock = -1; MQTTClients* m = NULL; MQTTPacket* pack = NULL; Thread_unlock_mutex(mqttclient_mutex); pack = MQTTClient_cycle(&sock, timeout, &rc); Thread_lock_mutex(mqttclient_mutex); if (tostop) break; timeout = 1000L; /* find client corresponding to socket */ if (ListFindItem(handles, &sock, clientSockCompare) == NULL) { /* assert: should not happen */ continue; } m = (MQTTClient)(handles->current->content); if (m == NULL) { /* assert: should not happen */ continue; } if (rc == SOCKET_ERROR) { if (m->c->connected) { Thread_unlock_mutex(mqttclient_mutex); MQTTClient_disconnect_internal(m, 0); Thread_lock_mutex(mqttclient_mutex); } else { if (m->c->connect_state == 2 && !Thread_check_sem(m->connect_sem)) { Log(TRACE_MIN, -1, "Posting connect semaphore for client %s", m->c->clientID); Thread_post_sem(m->connect_sem); } if (m->c->connect_state == 3 && !Thread_check_sem(m->connack_sem)) { Log(TRACE_MIN, -1, "Posting connack semaphore for client %s", m->c->clientID); Thread_post_sem(m->connack_sem); } } } else { if (m->c->messageQueue->count > 0) { qEntry* qe = (qEntry*)(m->c->messageQueue->first->content); int topicLen = qe->topicLen; if (strlen(qe->topicName) == topicLen) topicLen = 0; Log(TRACE_MIN, -1, "Calling messageArrived for client %s, queue depth %d", m->c->clientID, m->c->messageQueue->count); Thread_unlock_mutex(mqttclient_mutex); rc = (*(m->ma))(m->context, qe->topicName, topicLen, qe->msg); Thread_lock_mutex(mqttclient_mutex); /* if 0 (false) is returned by the callback then it failed, so we don't remove the message from * the queue, and it will be retried later. If 1 is returned then the message data may have been freed, * so we must be careful how we use it. */ if (rc) ListRemove(m->c->messageQueue, qe); else Log(TRACE_MIN, -1, "False returned from messageArrived for client %s, message remains on queue", m->c->clientID); } if (pack) { if (pack->header.bits.type == CONNACK && !Thread_check_sem(m->connack_sem)) { Log(TRACE_MIN, -1, "Posting connack semaphore for client %s", m->c->clientID); m->pack = pack; Thread_post_sem(m->connack_sem); } else if (pack->header.bits.type == SUBACK) { Log(TRACE_MIN, -1, "Posting suback semaphore for client %s", m->c->clientID); m->pack = pack; Thread_post_sem(m->suback_sem); } else if (pack->header.bits.type == UNSUBACK) { Log(TRACE_MIN, -1, "Posting unsuback semaphore for client %s", m->c->clientID); m->pack = pack; Thread_post_sem(m->unsuback_sem); } } else if (m->c->connect_state == 1 && !Thread_check_sem(m->connect_sem)) { int error; socklen_t len = sizeof(error); if ((m->rc = getsockopt(m->c->net.socket, SOL_SOCKET, SO_ERROR, (char*)&error, &len)) == 0) m->rc = error; Log(TRACE_MIN, -1, "Posting connect semaphore for client %s rc %d", m->c->clientID, m->rc); Thread_post_sem(m->connect_sem); } #if defined(OPENSSL) else if (m->c->connect_state == 2 && !Thread_check_sem(m->connect_sem)) { rc = SSLSocket_connect(m->c->net.ssl, m->c->net.socket); if (rc == 1 || rc == SSL_FATAL) { if (rc == 1 && !m->c->cleansession && m->c->session == NULL) m->c->session = SSL_get1_session(m->c->net.ssl); m->rc = rc; Log(TRACE_MIN, -1, "Posting connect semaphore for SSL client %s rc %d", m->c->clientID, m->rc); Thread_post_sem(m->connect_sem); } } #endif } } run_id = 0; running = tostop = 0; Thread_unlock_mutex(mqttclient_mutex); FUNC_EXIT; return 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; }
int MQTTClient_unsubscribeMany(MQTTClient handle, int count, char* const* topic) { MQTTClients* m = handle; List* topics = ListInitialize(); int i = 0; int rc = SOCKET_ERROR; int msgid = 0; FUNC_ENTRY; Thread_lock_mutex(mqttclient_mutex); if (m == NULL || m->c == NULL) { rc = MQTTCLIENT_FAILURE; goto exit; } if (m->c->connected == 0) { rc = MQTTCLIENT_DISCONNECTED; goto exit; } for (i = 0; i < count; i++) { if (!UTF8_validateString(topic[i])) { rc = MQTTCLIENT_BAD_UTF8_STRING; goto exit; } } if ((msgid = MQTTProtocol_assignMsgId(m->c)) == 0) { rc = MQTTCLIENT_MAX_MESSAGES_INFLIGHT; goto exit; } for (i = 0; i < count; i++) ListAppend(topics, topic[i], strlen(topic[i])); rc = MQTTProtocol_unsubscribe(m->c, topics, msgid); ListFreeNoContent(topics); if (rc == TCPSOCKET_COMPLETE) { MQTTPacket* pack = NULL; Thread_unlock_mutex(mqttclient_mutex); pack = MQTTClient_waitfor(handle, UNSUBACK, &rc, 10000L); Thread_lock_mutex(mqttclient_mutex); if (pack != NULL) { rc = MQTTProtocol_handleUnsubacks(pack, m->c->net.socket); m->pack = NULL; } else rc = SOCKET_ERROR; } if (rc == SOCKET_ERROR) { Thread_unlock_mutex(mqttclient_mutex); MQTTClient_disconnect_internal(handle, 0); Thread_lock_mutex(mqttclient_mutex); } exit: Thread_unlock_mutex(mqttclient_mutex); FUNC_EXIT_RC(rc); return rc; }
int MQTTClient_subscribeMany(MQTTClient handle, int count, char* const* topic, int* qos) { MQTTClients* m = handle; List* topics = ListInitialize(); List* qoss = ListInitialize(); int i = 0; int rc = MQTTCLIENT_FAILURE; int msgid = 0; FUNC_ENTRY; Thread_lock_mutex(mqttclient_mutex); if (m == NULL || m->c == NULL) { rc = MQTTCLIENT_FAILURE; goto exit; } if (m->c->connected == 0) { rc = MQTTCLIENT_DISCONNECTED; goto exit; } for (i = 0; i < count; i++) { if (!UTF8_validateString(topic[i])) { rc = MQTTCLIENT_BAD_UTF8_STRING; goto exit; } if(qos[i] < 0 || qos[i] > 2) { rc = MQTTCLIENT_BAD_QOS; goto exit; } } if ((msgid = MQTTProtocol_assignMsgId(m->c)) == 0) { rc = MQTTCLIENT_MAX_MESSAGES_INFLIGHT; goto exit; } for (i = 0; i < count; i++) { ListAppend(topics, topic[i], strlen(topic[i])); ListAppend(qoss, &qos[i], sizeof(int)); } rc = MQTTProtocol_subscribe(m->c, topics, qoss, msgid); ListFreeNoContent(topics); ListFreeNoContent(qoss); if (rc == TCPSOCKET_COMPLETE) { MQTTPacket* pack = NULL; Thread_unlock_mutex(mqttclient_mutex); pack = MQTTClient_waitfor(handle, SUBACK, &rc, 10000L); Thread_lock_mutex(mqttclient_mutex); if (pack != NULL) { Suback* sub = (Suback*)pack; ListElement* current = NULL; i = 0; while (ListNextElement(sub->qoss, ¤t)) { int* reqqos = (int*)(current->content); qos[i++] = *reqqos; } rc = MQTTProtocol_handleSubacks(pack, m->c->net.socket); m->pack = NULL; } else rc = SOCKET_ERROR; } if (rc == SOCKET_ERROR) { Thread_unlock_mutex(mqttclient_mutex); MQTTClient_disconnect_internal(handle, 0); Thread_lock_mutex(mqttclient_mutex); } else if (rc == TCPSOCKET_COMPLETE) rc = MQTTCLIENT_SUCCESS; exit: Thread_unlock_mutex(mqttclient_mutex); FUNC_EXIT_RC(rc); return rc; }
void MQTTProtocol_closeSession(Clients* c, int sendwill) { MQTTClient_disconnect_internal((MQTTClient)c->context, 0); }
int MQTTClient_subscribeMany(MQTTClient handle, int count, char** topic, int* qos) { MQTTClients* m = handle; List* topics = ListInitialize(); List* qoss = ListInitialize(); int i = 0; int rc = MQTTCLIENT_FAILURE; FUNC_ENTRY; Thread_lock_mutex(mqttclient_mutex); if (m == NULL || m->c == NULL) { rc = MQTTCLIENT_FAILURE; goto exit; } if (m->c->connected == 0) { rc = MQTTCLIENT_DISCONNECTED; goto exit; } for (i = 0; i < count; i++) { if (!UTF8_validateString(topic[i])) { rc = MQTTCLIENT_BAD_UTF8_STRING; goto exit; } } for (i = 0; i < count; i++) { ListAppend(topics, topic[i], strlen(topic[i])); ListAppend(qoss, &qos[i], sizeof(int)); } rc = MQTTProtocol_subscribe(m->c, topics, qoss); ListFreeNoContent(topics); ListFreeNoContent(qoss); if (rc == TCPSOCKET_COMPLETE) { MQTTPacket* pack = NULL; Thread_unlock_mutex(mqttclient_mutex); pack = MQTTClient_waitfor(handle, SUBACK, &rc, 10000L); Thread_lock_mutex(mqttclient_mutex); if (pack != NULL) { rc = MQTTProtocol_handleSubacks(pack, m->c->socket); m->pack = NULL; } else rc = SOCKET_ERROR; } if (rc == SOCKET_ERROR) { Thread_unlock_mutex(mqttclient_mutex); MQTTClient_disconnect_internal(handle, 0); Thread_lock_mutex(mqttclient_mutex); } else if (rc == TCPSOCKET_COMPLETE) rc = MQTTCLIENT_SUCCESS; exit: Thread_unlock_mutex(mqttclient_mutex); FUNC_EXIT_RC(rc); return rc; }