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_disconnect1(MQTTClient handle, int timeout, int internal, int stop) { MQTTClients* m = handle; START_TIME_TYPE start; int rc = MQTTCLIENT_SUCCESS; int was_connected = 0; FUNC_ENTRY; Thread_lock_mutex(mqttclient_mutex); if (m == NULL || m->c == NULL) { rc = MQTTCLIENT_FAILURE; goto exit; } if (m->c->connected == 0 && m->c->connect_state == 0) { rc = MQTTCLIENT_DISCONNECTED; goto exit; } was_connected = m->c->connected; /* should be 1 */ if (m->c->connected != 0) { start = MQTTClient_start_clock(); m->c->connect_state = -2; /* indicate disconnecting */ while (m->c->inboundMsgs->count > 0 || m->c->outboundMsgs->count > 0) { /* wait for all inflight message flows to finish, up to timeout */ if (MQTTClient_elapsed(start) >= timeout) break; Thread_unlock_mutex(mqttclient_mutex); MQTTClient_yield(); Thread_lock_mutex(mqttclient_mutex); } } MQTTClient_closeSession(m->c); while (Thread_check_sem(m->connect_sem)) Thread_wait_sem(m->connect_sem, 100); while (Thread_check_sem(m->connack_sem)) Thread_wait_sem(m->connack_sem, 100); while (Thread_check_sem(m->suback_sem)) Thread_wait_sem(m->suback_sem, 100); while (Thread_check_sem(m->unsuback_sem)) Thread_wait_sem(m->unsuback_sem, 100); exit: if (stop) MQTTClient_stop(); if (internal && m->cl && was_connected) { Log(TRACE_MIN, -1, "Calling connectionLost for client %s", m->c->clientID); Thread_start(connectionLost_call, m); } Thread_unlock_mutex(mqttclient_mutex); FUNC_EXIT_RC(rc); return rc; }
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; }
int MQTTClient_waitForCompletion(MQTTClient handle, MQTTClient_deliveryToken mdt, unsigned long timeout) { int rc = MQTTCLIENT_FAILURE; START_TIME_TYPE start = MQTTClient_start_clock(); unsigned long elapsed = 0L; MQTTClients* m = handle; 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; } if (ListFindItem(m->c->outboundMsgs, &mdt, messageIDCompare) == NULL) { rc = MQTTCLIENT_SUCCESS; /* well we couldn't find it */ goto exit; } elapsed = MQTTClient_elapsed(start); while (elapsed < timeout) { Thread_unlock_mutex(mqttclient_mutex); MQTTClient_yield(); Thread_lock_mutex(mqttclient_mutex); if (ListFindItem(m->c->outboundMsgs, &mdt, messageIDCompare) == NULL) { rc = MQTTCLIENT_SUCCESS; /* well we couldn't find it */ goto exit; } elapsed = MQTTClient_elapsed(start); } exit: Thread_unlock_mutex(mqttclient_mutex); FUNC_EXIT_RC(rc); return rc; }
int MQTTClient_connectURI(MQTTClient handle, MQTTClient_connectOptions* options, const char* serverURI) { MQTTClients* m = handle; START_TIME_TYPE start; long millisecsTimeout = 30000L; int rc = SOCKET_ERROR; int MQTTVersion = 0; FUNC_ENTRY; millisecsTimeout = options->connectTimeout * 1000; start = MQTTClient_start_clock(); m->c->keepAliveInterval = options->keepAliveInterval; m->c->cleansession = options->cleansession; m->c->maxInflightMessages = (options->reliable) ? 1 : 10; if (m->c->will) { free(m->c->will->msg); free(m->c->will->topic); free(m->c->will); m->c->will = NULL; } if (options->will && options->will->struct_version == 0) { m->c->will = malloc(sizeof(willMessages)); m->c->will->msg = MQTTStrdup(options->will->message); m->c->will->qos = options->will->qos; m->c->will->retained = options->will->retained; m->c->will->topic = MQTTStrdup(options->will->topicName); } #if defined(OPENSSL) if (m->c->sslopts) { if (m->c->sslopts->trustStore) free((void*)m->c->sslopts->trustStore); if (m->c->sslopts->keyStore) free((void*)m->c->sslopts->keyStore); if (m->c->sslopts->privateKey) free((void*)m->c->sslopts->privateKey); if (m->c->sslopts->privateKeyPassword) free((void*)m->c->sslopts->privateKeyPassword); if (m->c->sslopts->enabledCipherSuites) free((void*)m->c->sslopts->enabledCipherSuites); free(m->c->sslopts); m->c->sslopts = NULL; } if (options->struct_version != 0 && options->ssl) { m->c->sslopts = malloc(sizeof(MQTTClient_SSLOptions)); memset(m->c->sslopts, '\0', sizeof(MQTTClient_SSLOptions)); if (options->ssl->trustStore) m->c->sslopts->trustStore = MQTTStrdup(options->ssl->trustStore); if (options->ssl->keyStore) m->c->sslopts->keyStore = MQTTStrdup(options->ssl->keyStore); if (options->ssl->privateKey) m->c->sslopts->privateKey = MQTTStrdup(options->ssl->privateKey); if (options->ssl->privateKeyPassword) m->c->sslopts->privateKeyPassword = MQTTStrdup(options->ssl->privateKeyPassword); if (options->ssl->enabledCipherSuites) m->c->sslopts->enabledCipherSuites = MQTTStrdup(options->ssl->enabledCipherSuites); m->c->sslopts->enableServerCertAuth = options->ssl->enableServerCertAuth; } #endif m->c->username = options->username; m->c->password = options->password; m->c->retryInterval = options->retryInterval; if (options->struct_version >= 3) MQTTVersion = options->MQTTVersion; else MQTTVersion = MQTTVERSION_DEFAULT; if (MQTTVersion == MQTTVERSION_DEFAULT) { if ((rc = MQTTClient_connectURIVersion(handle, options, serverURI, 4, start, millisecsTimeout)) != MQTTCLIENT_SUCCESS) rc = MQTTClient_connectURIVersion(handle, options, serverURI, 3, start, millisecsTimeout); } else rc = MQTTClient_connectURIVersion(handle, options, serverURI, MQTTVersion, start, millisecsTimeout); FUNC_EXIT_RC(rc); return rc; }
MQTTPacket* MQTTClient_waitfor(MQTTClient handle, int packet_type, int* rc, long timeout) { MQTTPacket* pack = NULL; MQTTClients* m = handle; START_TIME_TYPE start = MQTTClient_start_clock(); FUNC_ENTRY; if (((MQTTClients*)handle) == NULL) { *rc = MQTTCLIENT_FAILURE; goto exit; } if (running) { if (packet_type == CONNECT) { if ((*rc = Thread_wait_sem(m->connect_sem, timeout)) == 0) *rc = m->rc; } else if (packet_type == CONNACK) *rc = Thread_wait_sem(m->connack_sem, timeout); else if (packet_type == SUBACK) *rc = Thread_wait_sem(m->suback_sem, timeout); else if (packet_type == UNSUBACK) *rc = Thread_wait_sem(m->unsuback_sem, timeout); if (*rc == 0 && packet_type != CONNECT && m->pack == NULL) Log(LOG_ERROR, -1, "waitfor unexpectedly is NULL for client %s, packet_type %d, timeout %ld", m->c->clientID, packet_type, timeout); pack = m->pack; } else { *rc = TCPSOCKET_COMPLETE; while (1) { int sock = -1; pack = MQTTClient_cycle(&sock, 100L, rc); if (sock == m->c->net.socket) { if (*rc == SOCKET_ERROR) break; if (pack && (pack->header.bits.type == packet_type)) break; if (m->c->connect_state == 1) { int error; socklen_t len = sizeof(error); if ((*rc = getsockopt(m->c->net.socket, SOL_SOCKET, SO_ERROR, (char*)&error, &len)) == 0) *rc = error; break; } #if defined(OPENSSL) else if (m->c->connect_state == 2) { *rc = SSLSocket_connect(m->c->net.ssl, sock); if (*rc == SSL_FATAL) break; else if (*rc == 1) /* rc == 1 means SSL connect has finished and succeeded */ { if (!m->c->cleansession && m->c->session == NULL) m->c->session = SSL_get1_session(m->c->net.ssl); break; } } #endif else if (m->c->connect_state == 3) { int error; socklen_t len = sizeof(error); if (getsockopt(m->c->net.socket, SOL_SOCKET, SO_ERROR, (char*)&error, &len) == 0) { if (error) { *rc = error; break; } } } } if (MQTTClient_elapsed(start) > timeout) { pack = NULL; break; } } } exit: FUNC_EXIT_RC(*rc); return pack; }
int MQTTClient_connect(MQTTClient handle, MQTTClient_connectOptions* options) { MQTTClients* m = handle; int rc = SOCKET_ERROR; START_TIME_TYPE start; long millisecsTimeout = 30000L; FUNC_ENTRY; Thread_lock_mutex(mqttclient_mutex); if (options == NULL) { rc = MQTTCLIENT_NULL_PARAMETER; goto exit; } if (strncmp(options->struct_id, "MQTC", 4) != 0 || options->struct_version != 0) { rc = MQTTCLIENT_BAD_STRUCTURE; goto exit; } if (options->will) /* check validity of will options structure */ { if (strncmp(options->will->struct_id, "MQTW", 4) != 0 || options->will->struct_version != 0) { rc = MQTTCLIENT_BAD_STRUCTURE; goto exit; } } if ((options->username && !UTF8_validateString(options->username)) || (options->password && !UTF8_validateString(options->password))) { rc = MQTTCLIENT_BAD_UTF8_STRING; goto exit; } millisecsTimeout = options->connectTimeout * 1000; start = MQTTClient_start_clock(); if (m->ma && !running) { Thread_start(MQTTClient_run, handle); if (MQTTClient_elapsed(start) >= millisecsTimeout) { rc = SOCKET_ERROR; goto exit; } MQTTClient_sleep(100L); } m->c->keepAliveInterval = options->keepAliveInterval; m->c->cleansession = options->cleansession; m->c->maxInflightMessages = (options->reliable) ? 1 : 10; if (options->will && options->will->struct_version == 0) { m->c->will = malloc(sizeof(willMessages)); m->c->will->msg = options->will->message; m->c->will->qos = options->will->qos; m->c->will->retained = options->will->retained; m->c->will->topic = options->will->topicName; } m->c->username = options->username; m->c->password = options->password; m->c->retryInterval = options->retryInterval; m->c->connectOptionsVersion = options->struct_version; Log(TRACE_MIN, -1, "Connecting to serverURI %s", m->serverURI); rc = MQTTProtocol_connect(m->serverURI, m->c); if (m->c->connect_state == 0) { rc = SOCKET_ERROR; goto exit; } if (m->c->connect_state == 1) { Thread_unlock_mutex(mqttclient_mutex); MQTTClient_waitfor(handle, CONNECT, &rc, millisecsTimeout - MQTTClient_elapsed(start)); Thread_lock_mutex(mqttclient_mutex); if (rc != 0) { rc = SOCKET_ERROR; goto exit; } m->c->connect_state = 2; /* TCP connect completed, in which case send the MQTT connect packet */ if (MQTTPacket_send_connect(m->c) == SOCKET_ERROR) { rc = SOCKET_ERROR; goto exit; } } if (m->c->connect_state == 2) { MQTTPacket* pack = NULL; Thread_unlock_mutex(mqttclient_mutex); pack = MQTTClient_waitfor(handle, CONNACK, &rc, millisecsTimeout - MQTTClient_elapsed(start)); Thread_lock_mutex(mqttclient_mutex); if (pack == NULL) rc = SOCKET_ERROR; else { Connack* connack = (Connack*)pack; if ((rc = connack->rc) == MQTTCLIENT_SUCCESS) { m->c->connected = 1; m->c->good = 1; m->c->connect_state = 3; time(&(m->c->lastContact)); if (m->c->cleansession) rc = MQTTClient_cleanSession(m->c); if (m->c->outboundMsgs->count > 0) { ListElement* outcurrent = NULL; while (ListNextElement(m->c->outboundMsgs, &outcurrent)) { Messages* m = (Messages*)(outcurrent->content); m->lastTouch = 0; } MQTTProtocol_retry(m->c->lastContact, 1); if (m->c->connected != 1) rc = MQTTCLIENT_DISCONNECTED; } } free(connack); m->pack = NULL; } } if (rc == SOCKET_ERROR || rc == MQTTCLIENT_PERSISTENCE_ERROR) { Thread_unlock_mutex(mqttclient_mutex); MQTTClient_disconnect(handle, 0); /* not "internal" because we don't want to call connection lost */ Thread_lock_mutex(mqttclient_mutex); } exit: if (m->c->will) { free(m->c->will); m->c->will = NULL; } Thread_unlock_mutex(mqttclient_mutex); FUNC_EXIT_RC(rc); return rc; }
MQTTPacket* MQTTClient_waitfor(MQTTClient handle, int packet_type, int* rc, long timeout) { MQTTPacket* pack = NULL; MQTTClients* m = handle; START_TIME_TYPE start = MQTTClient_start_clock(); FUNC_ENTRY; if (((MQTTClients*)handle) == NULL) { *rc = MQTTCLIENT_FAILURE; goto exit; } if (running) { if (packet_type == CONNECT) { if ((*rc = Thread_wait_sem(m->connect_sem)) == 0) *rc = m->rc; } else if (packet_type == CONNACK) *rc = Thread_wait_sem(m->connack_sem); else if (packet_type == SUBACK) *rc = Thread_wait_sem(m->suback_sem); else if (packet_type == UNSUBACK) *rc = Thread_wait_sem(m->unsuback_sem); if (*rc == 0 && packet_type != CONNECT && m->pack == NULL) Log(TRACE_MIN, -1, "waitfor unexpectedly is NULL for client %s, packet_type %d", m->c->clientID, packet_type); pack = m->pack; } else { *rc = TCPSOCKET_COMPLETE; while (1) { int sock = -1; pack = MQTTClient_cycle(&sock, 100L, rc); if (sock == m->c->socket) { if (pack && (pack->header.bits.type == packet_type)) break; if (m->c->connect_state == 1) { int error; socklen_t len = sizeof(error); if ((*rc = getsockopt(m->c->socket, SOL_SOCKET, SO_ERROR, (char*)&error, &len)) == 0) *rc = error; break; } } else if (MQTTClient_elapsed(start) > timeout) { pack = NULL; break; } } } exit: FUNC_EXIT_RC(*rc); return pack; }
int MQTTClient_connect(MQTTClient handle, MQTTClient_connectOptions* options) { MQTTClients* m = handle; int rc = SOCKET_ERROR; START_TIME_TYPE start; long millisecsTimeout = 30000L; FUNC_ENTRY; Thread_lock_mutex(mqttclient_mutex); if (options == NULL) { rc = MQTTCLIENT_NULL_PARAMETER; goto exit; } if (strncmp(options->struct_id, "MQTC", 4) != 0 || (options->struct_version != 0 && options->struct_version != 1)) { rc = MQTTCLIENT_BAD_STRUCTURE; goto exit; } if (options->will) /* check validity of will options structure */ { if (strncmp(options->will->struct_id, "MQTW", 4) != 0 || options->will->struct_version != 0) { rc = MQTTCLIENT_BAD_STRUCTURE; goto exit; } } #if defined(OPENSSL) if (options->struct_version != 0 && options->ssl) /* check validity of SSL options structure */ { if (strncmp(options->ssl->struct_id, "MQTS", 4) != 0 || options->ssl->struct_version != 0) { rc = MQTTCLIENT_BAD_STRUCTURE; goto exit; } } #endif if ((options->username && !UTF8_validateString(options->username)) || (options->password && !UTF8_validateString(options->password))) { rc = MQTTCLIENT_BAD_UTF8_STRING; goto exit; } millisecsTimeout = options->connectTimeout * 1000; start = MQTTClient_start_clock(); if (m->ma && !running) { Thread_start(MQTTClient_run, handle); if (MQTTClient_elapsed(start) >= millisecsTimeout) { rc = SOCKET_ERROR; goto exit; } MQTTClient_sleep(100L); } m->c->keepAliveInterval = options->keepAliveInterval; m->c->cleansession = options->cleansession; m->c->maxInflightMessages = (options->reliable) ? 1 : 10; if (options->will && options->will->struct_version == 0) { m->c->will = malloc(sizeof(willMessages)); m->c->will->msg = options->will->message; m->c->will->qos = options->will->qos; m->c->will->retained = options->will->retained; m->c->will->topic = options->will->topicName; } #if defined(OPENSSL) if (options->struct_version != 0 && options->ssl) m->c->sslopts = options->ssl; #endif m->c->username = options->username; m->c->password = options->password; m->c->retryInterval = options->retryInterval; Log(TRACE_MIN, -1, "Connecting to serverURI %s", m->serverURI); #if defined(OPENSSL) rc = MQTTProtocol_connect(m->serverURI, m->c, m->ssl); #else rc = MQTTProtocol_connect(m->serverURI, m->c); #endif if (rc == SOCKET_ERROR) goto exit; if (m->c->connect_state == 0) { rc = SOCKET_ERROR; goto exit; } if (m->c->connect_state == 1) /* TCP connect started - wait for completion */ { Thread_unlock_mutex(mqttclient_mutex); MQTTClient_waitfor(handle, CONNECT, &rc, millisecsTimeout - MQTTClient_elapsed(start)); Thread_lock_mutex(mqttclient_mutex); if (rc != 0) { rc = SOCKET_ERROR; goto exit; } #if defined(OPENSSL) if (m->ssl) { if (SSLSocket_setSocketForSSL(&m->c->net, m->c->sslopts) != MQTTCLIENT_SUCCESS) { if (m->c->session != NULL) if ((rc = SSL_set_session(m->c->net.ssl, m->c->session)) != 1) Log(TRACE_MIN, -1, "Failed to set SSL session with stored data, non critical"); rc = SSLSocket_connect(m->c->net.ssl, m->c->net.socket); if (rc == -1) m->c->connect_state = 2; else if (rc == SSL_FATAL) { rc = SOCKET_ERROR; goto exit; } else if (rc == 1 && !m->c->cleansession && m->c->session == NULL) m->c->session = SSL_get1_session(m->c->net.ssl); } else { rc = SOCKET_ERROR; goto exit; } } else { #endif m->c->connect_state = 3; /* TCP connect completed, in which case send the MQTT connect packet */ if (MQTTPacket_send_connect(m->c) == SOCKET_ERROR) { rc = SOCKET_ERROR; goto exit; } #if defined(OPENSSL) } #endif } #if defined(OPENSSL) if (m->c->connect_state == 2) /* SSL connect sent - wait for completion */ { Thread_unlock_mutex(mqttclient_mutex); MQTTClient_waitfor(handle, CONNECT, &rc, millisecsTimeout - MQTTClient_elapsed(start)); Thread_lock_mutex(mqttclient_mutex); if (rc != 1) { rc = SOCKET_ERROR; goto exit; } m->c->connect_state = 3; /* TCP connect completed, in which case send the MQTT connect packet */ if (MQTTPacket_send_connect(m->c) == SOCKET_ERROR) { rc = SOCKET_ERROR; goto exit; } } #endif if (m->c->connect_state == 3) /* MQTT connect sent - wait for CONNACK */ { MQTTPacket* pack = NULL; Thread_unlock_mutex(mqttclient_mutex); pack = MQTTClient_waitfor(handle, CONNACK, &rc, millisecsTimeout - MQTTClient_elapsed(start)); Thread_lock_mutex(mqttclient_mutex); if (pack == NULL) rc = SOCKET_ERROR; else { Connack* connack = (Connack*)pack; Log(LOG_PROTOCOL, 1, NULL, m->c->net.socket, m->c->clientID, connack->rc); if ((rc = connack->rc) == MQTTCLIENT_SUCCESS) { m->c->connected = 1; m->c->good = 1; m->c->connect_state = 0; if (m->c->cleansession) rc = MQTTClient_cleanSession(m->c); if (m->c->outboundMsgs->count > 0) { ListElement* outcurrent = NULL; while (ListNextElement(m->c->outboundMsgs, &outcurrent)) { Messages* m = (Messages*)(outcurrent->content); m->lastTouch = 0; } MQTTProtocol_retry(m->c->net.lastContact, 1); if (m->c->connected != 1) rc = MQTTCLIENT_DISCONNECTED; } } free(connack); m->pack = NULL; } } exit: if (rc != MQTTCLIENT_SUCCESS) { Thread_unlock_mutex(mqttclient_mutex); MQTTClient_disconnect(handle, 0); /* not "internal" because we don't want to call connection lost */ Thread_lock_mutex(mqttclient_mutex); } if (m->c->will) { free(m->c->will); m->c->will = NULL; } Thread_unlock_mutex(mqttclient_mutex); FUNC_EXIT_RC(rc); return rc; }