/** * Main broker startup function * @param argc number of elements of argv * @param argv command line strings * @return system return code */ int main(int argc, char* argv[]) { int rc = 0; #define BUILD_TIMESTAMP __DATE__ " " __TIME__ /* __TIMESTAMP__ */ #define BROKER_VERSION "1.2.0.12" /* __VERSION__ */ #define PRODUCT_NAME "MQTT Daemon for Devices" static char* broker_version_eye = NULL; static char* broker_timestamp_eye = NULL; FUNC_ENTRY_NOLOG; broker_timestamp_eye = "AMQTDD_Timestamp " BUILD_TIMESTAMP; broker_version_eye = "AMQTDD_Version " BROKER_VERSION; BrokerState.version = BROKER_VERSION; BrokerState.timestamp = BUILD_TIMESTAMP; srand(time(NULL)); Heap_initialize(); Log_initialize(); Log(LOG_INFO, 9999, PRODUCT_NAME); Log(LOG_INFO, 9998, "Part of Project Mosquitto in Eclipse\n(" "http://projects.eclipse.org/projects/technology.mosquitto)"); getopts(argc, argv); if (Messages_initialize(&BrokerState) != 0) goto no_messages; Log(LOG_INFO, 53, NULL, BrokerState.version, BrokerState.timestamp); Log(LOG_INFO, 54, "%s %s", Messages_get(54, LOG_INFO), "" #if !defined(NO_BRIDGE) " bridge" #endif #if defined(MQTTMP) " MQTTMP" #endif #if defined(MQTTS) " MQTTS" #endif ); if ((rc = Broker_startup()) == 0) { SubscriptionEngines_setRetained(BrokerState.se, "$SYS/broker/version", 0, BrokerState.version, strlen(BrokerState.version)); SubscriptionEngines_setRetained(BrokerState.se, "$SYS/broker/timestamp", 0, BrokerState.timestamp, strlen(BrokerState.timestamp)); while (BrokerState.state == BROKER_RUNNING) { Protocol_timeslice(); #if !defined(NO_BRIDGE) Bridge_timeslice(&BrokerState.bridge); #endif } Log(LOG_INFO, 46, NULL); #if !defined(NO_BRIDGE) Bridge_stop(&BrokerState.bridge); #endif while (BrokerState.state == BROKER_STOPPING) { Protocol_timeslice(); #if !defined(NO_BRIDGE) Bridge_timeslice(&BrokerState.bridge); #endif } } Broker_shutdown(rc); Log(LOG_INFO, 47, NULL); no_messages: Messages_terminate(); Log_terminate(); Heap_terminate(); /*FUNC_EXIT_NOLOG(rc); would anyone ever see this? */ return rc; }
/** * Originates a new publication - sends it to all clients subscribed. * @param publish pointer to a stucture which contains all the publication information * @param originator the originating client */ void Protocol_processPublication(Publish* publish, char* originator) { Messages* stored = NULL; /* to avoid duplication of data where possible */ List* clients; ListElement* current = NULL; int savedMsgId = publish->msgId; int clean_needed = 0; FUNC_ENTRY; if (Topics_hasWildcards(publish->topic)) { Log(LOG_INFO, 12, NULL, publish->topic, originator); goto exit; } if ((strcmp(INTERNAL_CLIENTID, originator) != 0) && bstate->password_file && bstate->acl_file) { Clients* client = (Clients*)(TreeFindIndex(bstate->clients, originator, 1)->content); if (Users_authorise(client->user, publish->topic, ACL_WRITE) == false) { Log(LOG_AUDIT, 149, NULL, originator, publish->topic); goto exit; } } if (publish->header.bits.retain) { SubscriptionEngines_setRetained(bstate->se, publish->topic, publish->header.bits.qos, publish->payload, publish->payloadlen); if (bstate->persistence == 1 && bstate->autosave_on_changes == 1 && bstate->autosave_interval > 0 && bstate->se->retained_changes >= bstate->autosave_interval) { Log(LOG_INFO, 100, NULL, bstate->autosave_interval); SubscriptionEngines_save(bstate->se); } } clients = SubscriptionEngines_getSubscribers(bstate->se, publish->topic, originator); if (strncmp(publish->topic, "$SYS/client/", 12) == 0) { /* default subscription for a client */ Node* node = TreeFindIndex(bstate->clients, &publish->topic[12], 1); if (node == NULL) node = TreeFind(bstate->disconnected_clients, &publish->topic[12]); if (node && node->content) { Subscriptions* rcs = malloc(sizeof(Subscriptions)); rcs->clientName = &publish->topic[12]; rcs->qos = 2; rcs->priority = PRIORITY_NORMAL; rcs->topicName = publish->topic; ListAppend(clients, rcs, sizeof(Subscriptions)); } } current = NULL; while (ListNextElement(clients, ¤t)) { Node* curnode = NULL; unsigned int qos = ((Subscriptions*)(current->content))->qos; int priority = ((Subscriptions*)(current->content))->priority; char* clientName = ((Subscriptions*)(current->content))->clientName; if (publish->header.bits.qos < qos) /* reduce qos if > subscribed qos */ qos = publish->header.bits.qos; if ((curnode = TreeFindIndex(bstate->clients, clientName, 1)) == NULL) curnode = TreeFind(bstate->disconnected_clients, clientName); #if defined(MQTTS) if (curnode == NULL && ((curnode = TreeFindIndex(bstate->mqtts_clients, clientName, 1)) == NULL)) curnode = TreeFind(bstate->disconnected_mqtts_clients, clientName); #endif if (curnode) { Clients* pubclient = (Clients*)(curnode->content); int retained = 0; Messages* saved = NULL; char* original_topic = publish->topic; #if !defined(NO_BRIDGE) if (pubclient->outbound || pubclient->noLocal) { retained = publish->header.bits.retain; /* outbound and noLocal mean outward/inward bridge client, so keep retained flag */ if (pubclient->outbound) { Bridge_handleOutbound(pubclient, publish); if (publish->topic != original_topic) { /* handleOutbound has changed the topic, so we musn't used the stored pub which contains the original topic */ saved = stored; stored = NULL; } } } #endif if (Protocol_startOrQueuePublish(pubclient, publish, qos, retained, priority, &stored) == SOCKET_ERROR) { pubclient->good = pubclient->connected = 0; /* flag this client as needing to be cleaned up */ clean_needed = 1; } if (publish->topic != original_topic) { stored = saved; /* restore the stored pointer for the next loop iteration */ free(publish->topic); publish->topic = original_topic; } } } publish->msgId = savedMsgId; /* INTERNAL_CLIENTID means that we are publishing data to the log, and we don't want to interfere with other close processing */ if (clean_needed && strcmp(originator, INTERNAL_CLIENTID) != 0) MQTTProtocol_clean_clients(bstate->clients); ListFree(clients); exit: FUNC_EXIT; }
/** * Main broker startup function * @param argc number of elements of argv * @param argv command line strings * @return system return code */ int main(int argc, char* argv[]) { int rc = 0; #define BUILD_TIMESTAMP __DATE__ " " __TIME__ /* __TIMESTAMP__ */ #define BROKER_VERSION "1.3.0.2" /* __VERSION__ */ #define PRODUCT_NAME "Really Small Message Broker" static char* broker_version_eye ATTR_UNUSED = NULL; static char* broker_timestamp_eye ATTR_UNUSED = NULL; FUNC_ENTRY_NOLOG; broker_timestamp_eye = "RSMB_Timestamp " BUILD_TIMESTAMP; broker_version_eye = "RSMB_Version " BROKER_VERSION; BrokerState.version = BROKER_VERSION; BrokerState.timestamp = BUILD_TIMESTAMP; Heap_initialize(); Log_initialize(); Log(LOG_INFO, 9999, PRODUCT_NAME); Log(LOG_INFO, 9998, "Part of Project Mosquitto in Eclipse\n(" "http://projects.eclipse.org/projects/technology.mosquitto)"); getopts(argc, argv); if (Messages_initialize(&BrokerState) != 0) goto no_messages; Log(LOG_INFO, 53, "Version %s, %s", BrokerState.version, BrokerState.timestamp); Log(LOG_INFO, 54, "Features included: %s", features); Log(LOG_INFO, 9993, "Authors: Ian Craggs ([email protected]), Nicholas O'Leary"); if ((rc = Broker_startup()) == 0) { SubscriptionEngines_setRetained(BrokerState.se, "$SYS/broker/version", 0, BrokerState.version, strlen(BrokerState.version)); SubscriptionEngines_setRetained(BrokerState.se, "$SYS/broker/timestamp", 0, BrokerState.timestamp, strlen(BrokerState.timestamp)); while (BrokerState.state == BROKER_RUNNING) { Protocol_timeslice(); #if !defined(NO_BRIDGE) Bridge_timeslice(&BrokerState.bridge); #endif } Log(LOG_INFO, 46, NULL); #if !defined(NO_BRIDGE) Bridge_stop(&BrokerState.bridge); #endif while (BrokerState.state == BROKER_STOPPING) { Protocol_timeslice(); #if !defined(NO_BRIDGE) Bridge_timeslice(&BrokerState.bridge); #endif } } Broker_shutdown(rc); Log(LOG_INFO, 47, NULL); no_messages: Messages_terminate(); Log_terminate(); Heap_terminate(); /*FUNC_EXIT_NOLOG(rc); would anyone ever see this? */ return rc; }