/** * Terminate the socket module for both in an outbound communications */ void Socket_terminate() { #if !defined(SINGLE_LISTENER) ListElement* current = NULL; #if defined(USE_POLL) struct socket_info* si = NULL; #endif FUNC_ENTRY; while (ListNextElement(s.listeners, ¤t)) { Listener* listener = (Listener*)(current->content); Socket_close_only(listener->socket); #if defined(USE_POLL) if ((si = TreeRemoveKey(s.fds_tree, &listener->socket)) == NULL) Log(LOG_WARNING, 13, "Failed to remove socket %d", listener->socket); else free(si); #endif } #else FUNC_ENTRY; Socket_close_only(s.mySocket); #endif Socket_outTerminate(); FUNC_EXIT; }
/** * 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. * We have to remove the item from the tree, as the memory is in order and so it needs to * be reinserted in the correct place. * @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; storageElement* s = NULL; Thread_lock_mutex(heap_mutex); s = TreeRemoveKey(&heap, ((int*)p)-1); if (s == NULL) Log(LOG_ERROR, 13, "Failed to reallocate heap item at file %s line %d", file, line); else { size_t space = sizeof(storageElement); size_t filenamelen = strlen(file)+1; checkEyecatchers(file, line, p, s->size); size = Heap_roundup(size); state.current_size += size - s->size; if (state.current_size > state.max_size) state.max_size = state.current_size; if ((s->ptr = realloc(s->ptr, size + 2*sizeof(int))) == NULL) { Log(LOG_ERROR, 13, errmsg); return NULL; } space += size + 2*sizeof(int) - s->size; *(int*)(s->ptr) = eyecatcher; /* start eyecatcher */ *(int*)(((char*)(s->ptr)) + (sizeof(int) + size)) = eyecatcher; /* end eyecatcher */ s->size = size; space -= strlen(s->file); s->file = realloc(s->file, filenamelen); space += filenamelen; strcpy(s->file, file); s->line = line; rc = s->ptr; TreeAdd(&heap, s, space); } Thread_unlock_mutex(heap_mutex); return (rc == NULL) ? NULL : ((int*)(rc)) + 1; /* skip start eyecatcher */ }
int MQTTSProtocol_handleConnects(void* pack, int sock, char* clientAddr, Clients* client, uint8_t* wirelessNodeId , uint8_t wirelessNodeIdLen) { MQTTS_Connect* connect = (MQTTS_Connect*)pack; Listener* list = NULL; int terminate = 0; Node* elem = NULL; int rc = 0; int existingClient = 0; FUNC_ENTRY; Log(LOG_PROTOCOL, 39, NULL, sock, clientAddr, client ? client->clientID : "", connect->flags.cleanSession); if (bstate->clientid_prefixes->count > 0 && !ListFindItem(bstate->clientid_prefixes, connect->clientID, clientPrefixCompare)) { Log(LOG_WARNING, 31, NULL, connect->clientID); terminate = 1; } else { list = Socket_getParentListener(sock); if (list->max_connections > -1 && list->connections->count > list->max_connections) { /* TODO: why is this commented out? delete if not needed //MQTTPacket_send_connack(3, sock); */ Log(LOG_WARNING, 141, NULL, connect->clientID, list->max_connections, list->port); terminate = 1; } else if (connect->protocolID != 1) { Log(LOG_WARNING, 32, NULL, "MQTT-S", connect->protocolID); /* TODO: why is this commented out? delete if not needed //MQTTPacket_send_connack(1, sock); */ terminate = 1; } } if (terminate) { /*TODO: process the terminate*/ MQTTSPacket_free_packet(pack); goto exit; } if (client != NULL && !strcmp(client->clientID, connect->clientID)) { /* Connect for a new client id on a used addr * TODO: clean out 'old' Client (that may be 'connected') */ } elem = TreeFindIndex(bstate->mqtts_clients, connect->clientID, 1); if (elem == NULL) { client = TreeRemoveKey(bstate->disconnected_mqtts_clients, connect->clientID); if (client == NULL) /* this is a totally new connection */ { /* Brand new client connection */ int i; client = malloc(sizeof(Clients)); memset(client, '\0', sizeof(Clients)); client->protocol = PROTOCOL_MQTTS; client->outboundMsgs = ListInitialize(); client->inboundMsgs = ListInitialize(); for (i = 0; i < PRIORITY_MAX; ++i) client->queuedMsgs[i] = ListInitialize(); client->registrations = ListInitialize(); client->noLocal = 0; /* (connect->version == PRIVATE_PROTOCOL_VERSION) ? 1 : 0; */ client->clientID = connect->clientID; connect->clientID = NULL; /* don't want to free this space as it is being used in the clients tree below */ // Set Wireless Node ID if exists if ( wirelessNodeId == NULL) { client->wirelessNodeId = NULL ; client->wirelessNodeIdLen = 0 ; } else { client->wirelessNodeId = malloc((sizeof(uint8_t) * wirelessNodeIdLen)) ; memcpy( client->wirelessNodeId , wirelessNodeId , sizeof(uint8_t) * wirelessNodeIdLen) ; client->wirelessNodeIdLen = wirelessNodeIdLen ; } } // // client == NULL else /* there is an existing disconnected client */ { /* Reconnect of a disconnected client */ free(client->addr); client->connect_state = 0; client->connected = 0; /* Do not connect until we know the connack has been sent */ // Delete Wireless Node ID if exists in existing client if ( wirelessNodeId == NULL) { if ( client->wirelessNodeId != NULL) free( client->wirelessNodeId ) ; client->wirelessNodeId = NULL ; client->wirelessNodeIdLen = 0 ; } else // Replace existing Wireless Node ID with value from current connect packet { if ( client->wirelessNodeId != NULL) free ( client->wirelessNodeId ) ; client->wirelessNodeId = malloc((sizeof(uint8_t) * wirelessNodeIdLen)) ; memcpy( client->wirelessNodeId , wirelessNodeId , sizeof(uint8_t) * wirelessNodeIdLen) ; client->wirelessNodeIdLen = wirelessNodeIdLen ; } } // client != NULL client->good = 1; /* good is set to 0 in disconnect, so we need to reset it here */ client->keepAliveInterval = connect->keepAlive; client->cleansession = connect->flags.cleanSession; client->socket = sock; client->addr = malloc(strlen(clientAddr)+1); strcpy(client->addr, clientAddr); TreeAdd(bstate->mqtts_clients, client, sizeof(Clients) + strlen(client->clientID)+1 + 3*sizeof(List)); if (client->cleansession) MQTTProtocol_removeAllSubscriptions(client->clientID); /* clear any persistent subscriptions */ if (connect->flags.will) { client->connect_state = 1; rc = MQTTSPacket_send_willTopicReq(client); } else { client->connected = 1; rc = MQTTSPacket_send_connack(client, 0); /* send response */ } } else { /* Reconnect of a connected client */ client = (Clients*)(elem->content); if (client->connected) { Log(LOG_INFO, 34, NULL, connect->clientID, clientAddr); if (client->socket != sock) Socket_close(client->socket); } client->socket = sock; client->connected = 0; /* Do not connect until we know the connack has been sent */ client->connect_state = 0; // Delete Wireless Node ID if exists in existing client if ( wirelessNodeId == NULL) { if ( client->wirelessNodeId != NULL) free( client->wirelessNodeId ) ; client->wirelessNodeId = NULL ; client->wirelessNodeIdLen = 0 ; } else // Replace existing Wireless Node ID with value from current connect packet { if ( client->wirelessNodeId != NULL) free ( client->wirelessNodeId ) ; client->wirelessNodeId = malloc((sizeof(uint8_t) * wirelessNodeIdLen)) ; memcpy( client->wirelessNodeId , wirelessNodeId , sizeof(uint8_t) * wirelessNodeIdLen) ; client->wirelessNodeIdLen = wirelessNodeIdLen ; } client->good = 1; if (client->addr != NULL) free(client->addr); client->addr = malloc(strlen(clientAddr)+1); strcpy(client->addr, clientAddr); client->cleansession = connect->flags.cleanSession; if (client->cleansession) { int i; MQTTProtocol_removeAllSubscriptions(client->clientID); /* empty pending message lists */ MQTTProtocol_emptyMessageList(client->outboundMsgs); MQTTProtocol_emptyMessageList(client->inboundMsgs); for (i = 0; i < PRIORITY_MAX; ++i) MQTTProtocol_emptyMessageList(client->queuedMsgs[i]); MQTTProtocol_clearWill(client); } /* registrations are always cleared */ MQTTSProtocol_emptyRegistrationList(client->registrations); /* have to remove and re-add client so it is in the right order for new socket */ if (client->socket != sock) { TreeRemoveNodeIndex(bstate->mqtts_clients, elem, 1); TreeRemoveKeyIndex(bstate->mqtts_clients, &client->socket, 0); client->socket = sock; TreeAdd(bstate->mqtts_clients, client, sizeof(Clients) + strlen(client->clientID)+1 + 3*sizeof(List)); } client->keepAliveInterval = connect->keepAlive; client->pendingRegistration = NULL; #if !defined(NO_BRIDGE) client->pendingSubscription = NULL; #endif if (connect->flags.will) { client->connect_state = 1; rc = MQTTSPacket_send_willTopicReq(client); } else { client->connected = 1; rc = MQTTSPacket_send_connack(client,0); /* send response */ } } if (existingClient) MQTTProtocol_processQueued(client); Log(LOG_INFO, 0, "Client connected to udp port %d from %s (%s)", list->port, client->clientID, clientAddr); MQTTSPacket_free_packet(pack); time( &(client->lastContact) ); exit: FUNC_EXIT_RC(rc); return rc; }
/** * Process an incoming connect packet for a socket * @param pack pointer to the connect packet * @param sock the socket on which the packet was received * @return completion code */ int MQTTProtocol_handleConnects(void* pack, int sock, Clients* client) { Connect* connect = (Connect*)pack; Node* elem = NULL; int terminate = 0; int rc = TCPSOCKET_COMPLETE; #if !defined(SINGLE_LISTENER) Listener* listener = Socket_getParentListener(sock); #endif FUNC_ENTRY; Log(LOG_PROTOCOL, 26, NULL, sock, connect->clientID);/* connect->Protocol, connect->flags.bits.cleanstart, connect->keepAliveTimer, connect->version, connect->username, connect->password);*/ Socket_removeNew(sock); if (bstate->state != BROKER_RUNNING) terminate = 1; /* don't accept new connection requests when we are shutting down */ /* Now check the version. If we don't recognize it we will not have parsed the packet, * so nothing else in the packet structure will have been filled in. */ else if (!MQTTPacket_checkVersion(pack)) { Log(LOG_WARNING, 32, NULL, connect->Protocol, connect->version); rc = MQTTPacket_send_connack(CONNACK_UNACCEPTABLE_PROTOCOL_VERSION, sock, Socket_getpeer(sock)); /* send response */ terminate = 1; } else if (connect->clientID[0] == '\0' || (connect->version == 3 && strlen(connect->clientID) > 23)) { rc = MQTTPacket_send_connack(CONNACK_IDENTIFIER_REJECTED, sock, Socket_getpeer(sock)); /* send response */ terminate = 1; } else if (bstate->password_file != NULL) { if (connect->flags.bits.username && connect->flags.bits.password && (Users_authenticate(connect->username, connect->password) == false)) { Log(LOG_WARNING, 31, NULL, connect->clientID); rc = MQTTPacket_send_connack(CONNACK_BAD_USERNAME_OR_PASSWORD, sock, connect->clientID); /* send bad user/pass response */ terminate = 1; } else if ((!connect->flags.bits.username || !connect->flags.bits.password) && !bstate->allow_anonymous) { Log(LOG_WARNING, 31, NULL, connect->clientID); rc = MQTTPacket_send_connack(CONNACK_BROKER_UNAVAILABLE, sock, connect->clientID); /* send broker unavailable response */ terminate = 1; } } if (terminate) ; else if (bstate->clientid_prefixes->count > 0 && !ListFindItem(bstate->clientid_prefixes, connect->clientID, clientPrefixCompare)) { Log(LOG_WARNING, 31, NULL, connect->clientID); terminate = 1; } else { #if !defined(SINGLE_LISTENER) if (listener->max_connections > -1 && listener->connections->count > listener->max_connections) { Log(LOG_WARNING, 141, NULL, connect->clientID, listener->max_connections, listener->port); #else if (bstate->max_connections > -1 && MQTTProtocol_getNoConnectedClients() >= bstate->max_connections) { Log(LOG_WARNING, 141, NULL, connect->clientID, bstate->max_connections, bstate->port); #endif rc = MQTTPacket_send_connack(CONNACK_BROKER_UNAVAILABLE, sock, connect->clientID); /* send response */ terminate = 1; } } if (terminate) { MQTTPacket_freeConnect(connect); Socket_close(sock); rc = TCPSOCKET_COMPLETE; goto exit; } if (bstate->connection_messages) Log(LOG_INFO, #if !defined(SINGLE_LISTENER) 33, NULL, listener->port, connect->clientID, Socket_getpeer(sock)); #else 33, NULL, bstate->port, connect->clientID, Socket_getpeer(sock)); #endif elem = TreeFindIndex(bstate->clients, connect->clientID, 1); if (elem == NULL) { client = TreeRemoveKey(bstate->disconnected_clients, connect->clientID); if (client == NULL) { int i; char* tmpAddr = NULL; client = malloc(sizeof(Clients)); memset(client, '\0', sizeof(Clients)); tmpAddr = Socket_getpeer(sock); client->addr = malloc(strlen(tmpAddr)+1); strcpy(client->addr, tmpAddr); #if defined(MQTTS) client->protocol = PROTOCOL_MQTT; #endif client->clientID = connect->clientID; client->outboundMsgs = ListInitialize(); client->inboundMsgs = ListInitialize(); for (i = 0; i < PRIORITY_MAX; ++i) client->queuedMsgs[i] = ListInitialize(); connect->clientID = NULL; /* don't want to free this space as it is being used in the client structure */ } client->socket = sock; TreeAdd(bstate->clients, client, sizeof(Clients) + strlen(client->clientID)+1 + 3*sizeof(List)); } else { client = (Clients*)(elem->content); if (client->connected) { Log(LOG_INFO, 34, NULL, connect->clientID, Socket_getpeer(sock)); if (client->socket != sock) Socket_close(client->socket); } if (connect->flags.bits.cleanstart) { int i; /* empty pending message lists */ MQTTProtocol_emptyMessageList(client->outboundMsgs); MQTTProtocol_emptyMessageList(client->inboundMsgs); for (i = 0; i < PRIORITY_MAX; ++i) MQTTProtocol_emptyMessageList(client->queuedMsgs[i]); client->msgID = client->outbound = client->ping_outstanding = 0; } /* have to remove and re-add client so it is in the right order for new socket */ if (client->socket != sock) { TreeRemoveNodeIndex(bstate->clients, elem, 1); TreeRemoveKeyIndex(bstate->clients, &client->socket, 0); client->socket = sock; TreeAdd(bstate->clients, client, sizeof(Clients) + strlen(client->clientID)+1 + 3*sizeof(List)); } } client->good = client->connected = 1; client->cleansession = connect->flags.bits.cleanstart; client->keepAliveInterval = connect->keepAliveTimer; client->noLocal = (connect->version == PRIVATE_PROTOCOL_VERSION) ? 1 : 0; if (client->cleansession) MQTTProtocol_removeAllSubscriptions(client->clientID); /* clear any persistent subscriptions */ #if !defined(SINGLE_LISTENER) if (listener && listener->mount_point && connect->flags.bits.will) { char* temp = malloc(strlen(connect->willTopic) + strlen(listener->mount_point) + 1); strcpy(temp, listener->mount_point); strcat(temp, connect->willTopic); free(connect->willTopic); connect->willTopic = temp; } #endif #if defined(MQTTS) if (connect->flags.bits.will) { MQTTProtocol_setWillTopic(client, connect->willTopic, connect->flags.bits.willRetain, connect->flags.bits.willQoS); MQTTProtocol_setWillMsg(client, connect->willMsg); connect->willTopic = NULL; connect->willMsg = NULL; } #else MQTTProtocol_setWill(connect, client); #endif if (connect->flags.bits.username) { client->user = Users_get_user(connect->username); } rc = MQTTPacket_send_connack(CONNACK_CONNECTION_ACCEPTED, sock, client->clientID); /* send response */ if (client->cleansession == 0) { ListElement* outcurrent = NULL; time_t now = 0; /* ensure that inflight messages are retried now by setting the last touched time * to very old (0) before calling the retry function */ time(&(now)); while (ListNextElement(client->outboundMsgs, &outcurrent)) { Messages* m = (Messages*)(outcurrent->content); m->lastTouch = 0; } MQTTProtocol_retries(now, client); MQTTProtocol_processQueued(client); } time(&(client->lastContact)); MQTTPacket_freeConnect(connect); exit: FUNC_EXIT_RC(rc); return rc; } /** * Process an incoming ping request packet for a socket * @param pack pointer to the publish packet * @param sock the socket on which the packet was received * @return completion code */ int MQTTProtocol_handlePingreqs(void* pack, int sock, Clients* client) { int rc = TCPSOCKET_COMPLETE; FUNC_ENTRY; Log(LOG_PROTOCOL, 3, NULL, sock, client->clientID); rc = MQTTPacket_send_pingresp(sock, client->clientID); FUNC_EXIT_RC(rc); return rc; }