/** * Reallocates a block of memory. A direct replacement for realloc, but keeps track of items * allocated in a list, so that free can check that a item is being freed correctly and that * we can check that all memory is freed at shutdown. * @param file use the __FILE__ macro to indicate which file this item was reallocated in * @param line use the __LINE__ macro to indicate which line this item was reallocated at * @param p pointer to the item to be reallocated * @param size the new size of the item * @return pointer to the allocated item, or NULL if there was an error */ void *myrealloc(char* file, int line, void* p, size_t size) { void* rc = NULL; ListElement* e = ListFindItem(&heap, p, ptrCompare); if (e == NULL) Log(LOG_ERROR, -1, "Failed to reallocate heap item at file %s line %d", file, line); else { storageElement* s = (storageElement*)(heap.current->content); state.current_size += size - s->size; if (state.current_size > state.max_size) state.max_size = state.current_size; rc = s->ptr = realloc(s->ptr, size); s->size = size; s->file = realloc(s->file, strlen(file)+1); strcpy(s->file, file); s->line = line; if (s->stack) { free(s->stack); s->stack = StackTrace_get(Thread_getid()); } } return rc; }
void MQTTClient_stop() { int rc = 0; FUNC_ENTRY; if (running == 1 && tostop == 0) { int conn_count = 0; ListElement* current = NULL; if (handles != NULL) { /* find out how many handles are still connected */ while (ListNextElement(handles, ¤t)) { if (((MQTTClients*)(current->content))->c->connect_state > 0 || ((MQTTClients*)(current->content))->c->connected) ++conn_count; } } Log(TRACE_MIN, -1, "Conn_count is %d", conn_count); /* stop the background thread, if we are the last one to be using it */ if (conn_count == 0) { int count = 0; tostop = 1; if (Thread_getid() != run_id) { while (running && ++count < 100) { Thread_unlock_mutex(mqttclient_mutex); Log(TRACE_MIN, -1, "sleeping"); MQTTClient_sleep(100L); Thread_lock_mutex(mqttclient_mutex); } } rc = 1; } } FUNC_EXIT_RC(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; }
/** * Allocates a block of memory. A direct replacement for malloc, but keeps track of items * allocated in a list, so that free can check that a item is being freed correctly and that * we can check that all memory is freed at shutdown. * @param file use the __FILE__ macro to indicate which file this item was allocated in * @param line use the __LINE__ macro to indicate which line this item was allocated at * @param size the size of the item to be allocated * @return pointer to the allocated item, or NULL if there was an error */ void* mymalloc(char* file, int line, size_t size) { ListElement* e = NULL; storageElement* s = NULL; static char* errmsg = "Memory allocation error"; if ((s = malloc(sizeof(storageElement))) == NULL) { Log(LOG_ERROR, -1, errmsg); return NULL; } if ((s->file = malloc(strlen(file)+1)) == NULL) { Log(LOG_ERROR, -1, errmsg); free(s); return NULL; } strcpy(s->file, file); s->line = line; if ((s->ptr = malloc(size)) == NULL) { Log(LOG_ERROR, -1, errmsg); free(s->file); free(s); return NULL; } s->size = size; s->stack = NULL; if (trace_settings.trace_level == TRACE_MAXIMUM) { if ((s->stack = StackTrace_get(Thread_getid())) == NULL) { Log(LOG_ERROR, -1, errmsg); free(s->ptr); free(s->file); free(s); return NULL; } else { Log(TRACE_MAX, -1, "Allocating %d bytes in heap at line %d of file %s, ptr %p, heap use now %d bytes", s->size, line, file, s->ptr, state.current_size); Log(TRACE_MAX, -1, "Stack trace is %s", s->stack); } } if ((e = malloc(sizeof(ListElement))) == NULL) { Log(LOG_ERROR, -1, errmsg); if (s->stack) free(s->stack); free(s->ptr); free(s->file); free(s); return NULL; } ListAppendNoMalloc(&heap, s, e, sizeof(ListElement)); state.current_size += size; if (state.current_size > state.max_size) state.max_size = state.current_size; return s->ptr; }