mirror of
https://github.com/nanomq/nanomq.git
synced 2025-05-04 03:06:43 +00:00
* NEW [nanomq-nng] Ver 0.0.1 release
This commit is contained in:
parent
e075263a55
commit
eca9dd8327
35
CMakeLists.txt
Normal file
35
CMakeLists.txt
Normal file
@ -0,0 +1,35 @@
|
||||
|
||||
#
|
||||
# This software is supplied under the terms of the MIT License, a
|
||||
# copy of which should be located in the distribution where this
|
||||
# file was obtained (LICENSE.txt). A copy of the license may also be
|
||||
# found online at https://opensource.org/licenses/MIT.
|
||||
# not finished yet #
|
||||
|
||||
cmake_minimum_required (VERSION 2.8.8)
|
||||
|
||||
project(nanomq-nng)
|
||||
|
||||
set(CMAKE_MODULE_PATH
|
||||
${CMAKE_MODULE_PATH}
|
||||
"${CMAKE_CURRENT_LIST_DIR}/cmake"
|
||||
)
|
||||
|
||||
option(NOLOG "build this project nolog" OFF)
|
||||
|
||||
if (NOLOG)
|
||||
add_definitions(-DNOLOG)
|
||||
endif (NOLOG)
|
||||
|
||||
#add_executable(nanomq-nng nanomq/nanomq.c)
|
||||
|
||||
#add_dependencies(nanomq-nng nng_h)
|
||||
|
||||
|
||||
add_subdirectory(nng)
|
||||
add_subdirectory(nanolib)
|
||||
add_subdirectory(nanomq)
|
||||
|
||||
|
||||
add_dependencies(nanomq nng)
|
||||
add_dependencies(nanomq nanolib)
|
84
README.md
84
README.md
@ -1,7 +1,83 @@
|
||||
# nanomq
|
||||
# NanoMQ
|
||||
|
||||
Nano MQTT Broker - A Ultra-light and Blazing-fast MQTT 5.0 Broker for IoT Edge.
|
||||
Nano MQTT Broker
|
||||
|
||||
# Author
|
||||
A light-weight and Blazing-fast MQTT 5.0 Broker for IoT Edge platform.
|
||||
|
||||
EMQ X Team.
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
1. Cost-effective on embedded platform.
|
||||
2. Fully base on native POSIX. High Compatibility.
|
||||
3. Pure C/C++ implementation. High portability.
|
||||
4. Fully asynchronous I/O and multi-threading.
|
||||
5. Good support for SMP.
|
||||
6. Low latency & High handling capacity.
|
||||
|
||||
|
||||
|
||||
## QuickStart
|
||||
|
||||
1. Compile & Install
|
||||
|
||||
NanoMQ is base on NNG's asynchronous I/O threading model. With rewriting the TCP/SP part with self-added protocol: nano_tcp.
|
||||
|
||||
To build this whole project, you will need a C99 compatible & C++11 compiler and [CMake](http://www.cmake.org/) version 3.13 or newer.
|
||||
|
||||
Basically you just need to simply compile and install nanomq by:
|
||||
|
||||
$PROJECT_PATH/nanomq$ mkdir build & cd build
|
||||
|
||||
$PROJECT_PATH/nanomq/build$ cmake -G Ninja ..
|
||||
|
||||
$PROJECT_PATH/nanomq/build$ sudo ninja install
|
||||
|
||||
or you can limit threads by
|
||||
cmake -G Ninja -DNNG_RESOLV_CONCURRENCY=1 -DNNG_NUM_TASKQ_THREADS=5 -DNNG_MAX_TASKQ_THREADS=5 ..
|
||||
|
||||
Please be aware that nanomq depends on nanolib & nng (MQTT ver)
|
||||
|
||||
both dependencies can be complied independently
|
||||
|
||||
$PROJECT_PATH/nanomq/nng/build$ cmake -G Ninja ..
|
||||
$PROJECT_PATH/nanomq/nng/build$ ninja install
|
||||
|
||||
compile nanolib independently:
|
||||
$PROJECT_PATH/nanolib/build$ cmake -G Ninja ..
|
||||
$PROJECT_PATH/nanolib/build$ ninja install
|
||||
|
||||
In short future, We will implement a way to let nanomq support MQTT without damaging NNG's SP support.
|
||||
Also rewrite CMake and MakeFile so that user can easily choose which ver of nng to base on.
|
||||
|
||||
TODO:
|
||||
|
||||
more features coming
|
||||
|
||||
===============================================
|
||||
|
||||
2. Usage:
|
||||
|
||||
#ongoing MQTT Broker
|
||||
sudo ./nanomq broker start 'tcp://localhost:1883' &
|
||||
|
||||
#test POSIX message Queue
|
||||
sudo ./nanomq broker mq start/stop
|
||||
|
||||
## Communties
|
||||
|
||||
You can Join us on Slack channel:
|
||||
|
||||
#nanomq: general usage
|
||||
|
||||
#nanomq-dev : for MQTT lover & developer
|
||||
|
||||
#nanomq-nng : for users & nng project.
|
||||
|
||||
|
||||
|
||||
More communities on github, slack, reddit, twitter, gitter, discord are coming soon.
|
||||
|
||||
## Authors
|
||||
|
||||
The EMQ X team.
|
66
nanolib/CMakeLists.txt
Normal file
66
nanolib/CMakeLists.txt
Normal file
@ -0,0 +1,66 @@
|
||||
#
|
||||
# This software is supplied under the terms of the MIT License, a
|
||||
# copy of which should be located in the distribution where this
|
||||
# file was obtained (LICENSE.txt). A copy of the license may also be
|
||||
# found online at https://opensource.org/licenses/MIT.
|
||||
|
||||
cmake_minimum_required (VERSION 2.8.8)
|
||||
|
||||
project(nanolib)
|
||||
|
||||
SET(CMAKE_CXX_FLAGS "-std=c++11 -O3")
|
||||
|
||||
set(DEFAULT_BUILD_TYPE "Release")
|
||||
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
message(STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.")
|
||||
set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE)
|
||||
# Set the possible values of build type for cmake-gui
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
|
||||
endif()
|
||||
|
||||
#aux_source_directory(. DIRSRCS)
|
||||
|
||||
include_directories(./include)
|
||||
|
||||
#add_subdirectory(./packet_parser)
|
||||
|
||||
# Call this from your own project's makefile.
|
||||
# find_package(nng CONFIG REQUIRED)
|
||||
|
||||
# list of source files
|
||||
set(libsrc hash.cc mqtt_db.c zmalloc.c)
|
||||
|
||||
# this is the "object library" target: compiles the sources only once
|
||||
add_library(nanolib OBJECT ${libsrc})
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
PRIVATE src)
|
||||
|
||||
# shared libraries need PIC
|
||||
set_property(TARGET nanolib PROPERTY POSITION_INDEPENDENT_CODE 1)
|
||||
#set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION 1)
|
||||
|
||||
# shared and static libraries built from the same object files
|
||||
add_library(nano_shared SHARED $<TARGET_OBJECTS:nanolib>)
|
||||
#add_library(nanolib_static STATIC $<TARGET_OBJECTS:nanolib>)
|
||||
|
||||
|
||||
add_executable(test test.c)
|
||||
target_link_libraries(test nano_shared)
|
||||
|
||||
|
||||
install(TARGETS nano_shared EXPORT nanolibConfig
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})
|
||||
|
||||
install(EXPORT nanolibConfig DESTINATION share/nanolib/cmake)
|
||||
|
||||
export(TARGETS ${PROJECT_NAME} FILE nanolibConfig.cmake)
|
||||
add_custom_target(nanodist COMMAND ${CMAKE_MAKE_PROGRAM} package_source)
|
29
nanolib/Makefile
Normal file
29
nanolib/Makefile
Normal file
@ -0,0 +1,29 @@
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -g -fPIC
|
||||
INC = -I./inlcude
|
||||
OBJ = mqtt_db.o zmalloc.o hash.o
|
||||
DLIBS = -lnano
|
||||
LDFLAGS = -L.
|
||||
RPATH = -Wl,-rpath=.
|
||||
DESTDIR = /usr/local/include/
|
||||
|
||||
|
||||
|
||||
all:nanolib test.c
|
||||
$(CC) -o nano test.c $(CFLAGS) $(LDFLAGS) $(DLIBS) $(RPATH)
|
||||
./nano
|
||||
|
||||
%.o:%.c $(INC)
|
||||
$(CC) -c -o $@ $< $(CFLAGS)
|
||||
|
||||
hash.o:hash.cc
|
||||
g++ -c -o hash.o hash.cc -Wall -g -fPIC
|
||||
|
||||
nanolib:$(OBJ)
|
||||
$(CC) -shared -fPIC -o libnano.so $(OBJ) -lstdc++
|
||||
rm -f $(OBJ)
|
||||
|
||||
|
||||
.PHONY:clean
|
||||
clean:
|
||||
rm -f $(OBJ) libnano.so nano
|
257
nanolib/hash.cc
Normal file
257
nanolib/hash.cc
Normal file
@ -0,0 +1,257 @@
|
||||
#include <unordered_map>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <cstdlib>
|
||||
#include "include/dbg.h"
|
||||
#include "include/hash.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
template<typename K, typename V>
|
||||
class mqtt_hash {
|
||||
public:
|
||||
typedef typename unordered_map<K, V>::iterator iterator;
|
||||
|
||||
V &operator [](const K &_key)
|
||||
{
|
||||
lock_guard<mutex> lk(_mtx);
|
||||
return hash_map[_key];
|
||||
}
|
||||
|
||||
V get(const K &_key)
|
||||
{
|
||||
lock_guard<mutex> lk(_mtx);
|
||||
return hash_map[_key];
|
||||
}
|
||||
|
||||
void set(const K &_key, const V &_val)
|
||||
{
|
||||
lock_guard<mutex> lk(_mtx);
|
||||
hash_map[_key] = _val;
|
||||
}
|
||||
|
||||
void del(const K &_key)
|
||||
{
|
||||
lock_guard<mutex> lk(_mtx);
|
||||
mqtt_hash<K, V>::iterator iter = hash_map.find(_key);
|
||||
|
||||
if (iter != hash_map.end()) {
|
||||
hash_map.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
bool find(const K &_key)
|
||||
{
|
||||
mqtt_hash<K, V>::iterator iter = hash_map.begin();
|
||||
iter = hash_map.find(_key);
|
||||
|
||||
if (iter != hash_map.end()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
unordered_map<K, V> hash_map;
|
||||
mutex _mtx;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
mqtt_hash<int, char*> _mqtt_hash;
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
void push_val(int key, char *val)
|
||||
{
|
||||
_mqtt_hash[key] = val;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
char *get_val(int key)
|
||||
{
|
||||
return _mqtt_hash.get(key);
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
void del_val(int key)
|
||||
{
|
||||
_mqtt_hash.del(key);
|
||||
|
||||
}
|
||||
|
||||
mqtt_hash<char *, topic_queue *> _topic_hash;
|
||||
|
||||
struct topic_queue *new_topic_queue(char *val)
|
||||
{
|
||||
struct topic_queue *tq = NULL;
|
||||
int len = strlen(val);
|
||||
|
||||
tq = (struct topic_queue*)malloc(sizeof(struct topic_queue));
|
||||
if (!tq) {
|
||||
fprintf(stderr, "zmalloc: Out of memory\n");
|
||||
fflush(stderr);
|
||||
abort();
|
||||
|
||||
}
|
||||
tq->topic = (char*)malloc(sizeof(char)*(len+1));
|
||||
if (!tq->topic) {
|
||||
fprintf(stderr, "zmalloc: Out of memory\n");
|
||||
fflush(stderr);
|
||||
abort();
|
||||
|
||||
}
|
||||
memcpy(tq->topic, val, len);
|
||||
tq->topic[len] = '\0';
|
||||
tq->next = NULL;
|
||||
|
||||
return tq;
|
||||
}
|
||||
|
||||
void delete_topic_queue(struct topic_queue *tq)
|
||||
{
|
||||
if (tq) {
|
||||
if (tq->topic) {
|
||||
log("delete topic:%s", tq->topic);
|
||||
free(tq->topic);
|
||||
tq->topic = NULL;
|
||||
}
|
||||
free(tq);
|
||||
tq = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
void add_topic(char *id, char *val)
|
||||
{
|
||||
struct topic_queue *ntq = new_topic_queue(val);
|
||||
struct topic_queue *tq = _topic_hash[id];
|
||||
if (tq == NULL) {
|
||||
_topic_hash[id] = ntq;
|
||||
log("add_topic:%s",_topic_hash[id]->topic);
|
||||
} else {
|
||||
struct topic_queue *tmp = tq->next;
|
||||
tq->next = ntq;
|
||||
ntq->next = tmp;
|
||||
log("add_topic:%s", tq->next->topic);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
struct topic_queue *get_topic(char *id)
|
||||
{
|
||||
if (_topic_hash[id]) {
|
||||
return _topic_hash[id];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
void del_topic_one(char *id, char *topic)
|
||||
{
|
||||
struct topic_queue *tt = _topic_hash[id];
|
||||
struct topic_queue *tb = NULL;
|
||||
|
||||
if (!strcmp(tt->topic, topic) && tt->next == NULL) {
|
||||
_topic_hash.del(id);
|
||||
delete_topic_queue(tt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcmp(tt->topic, topic)) {
|
||||
_topic_hash[id] = tt->next;
|
||||
delete_topic_queue(tt);
|
||||
return;
|
||||
}
|
||||
|
||||
while (tt) {
|
||||
if (!strcmp(tt->topic, topic)) {
|
||||
if (tt->next == NULL) {
|
||||
tb->next = NULL;
|
||||
} else {
|
||||
tb->next = tt->next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
tb = tt;
|
||||
tt = tt->next;
|
||||
}
|
||||
|
||||
delete_topic_queue(tt);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
void del_topic_all(char *id)
|
||||
{
|
||||
struct topic_queue *tq = _topic_hash[id];
|
||||
_topic_hash.del(id);
|
||||
while (tq) {
|
||||
struct topic_queue *tt = tq;
|
||||
tq = tq->next;
|
||||
delete_topic_queue(tt);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
bool check_id(char *id)
|
||||
{
|
||||
return _topic_hash.find(id);
|
||||
}
|
||||
|
||||
|
||||
mqtt_hash<uint32_t, char *> _pipe_hash;
|
||||
|
||||
void add_pipe_id(uint32_t pipe_id, char *client_id)
|
||||
{
|
||||
_pipe_hash[pipe_id] = client_id;
|
||||
log("add_pipe_id %d, client_id %s", pipe_id, _pipe_hash[pipe_id]);
|
||||
return;
|
||||
}
|
||||
|
||||
void del_pipe_id(uint32_t pipe_id)
|
||||
{
|
||||
#ifdef NOLOG
|
||||
#else
|
||||
char *res = _pipe_hash[pipe_id];
|
||||
#endif
|
||||
log("del_pipe_id %d, client_id %s", pipe_id, res);
|
||||
_pipe_hash.del(pipe_id);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
char *get_client_id(uint32_t pipe_id)
|
||||
{
|
||||
return _pipe_hash[pipe_id];
|
||||
}
|
||||
|
||||
bool check_pipe_id(uint32_t pipe_id)
|
||||
{
|
||||
return _pipe_hash.find(pipe_id);
|
||||
}
|
||||
|
||||
|
66
nanolib/include/dbg.h
Normal file
66
nanolib/include/dbg.h
Normal file
@ -0,0 +1,66 @@
|
||||
#ifndef __dbg_h__
|
||||
#define __dbg_h__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
|
||||
static inline char *nano_get_time()
|
||||
{
|
||||
char *buffer;
|
||||
time_t now;
|
||||
|
||||
now = time(NULL);
|
||||
buffer = ctime(&now);
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
|
||||
if (buffer[strlen(buffer) - 1] == '\n')
|
||||
buffer[strlen(buffer) - 1] = '\0';
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define debug(M, ...)
|
||||
#else
|
||||
#define debug(M, ...) fprintf(stderr, "[DEBUG] %s:%d: " M "\n",\
|
||||
__FILE__, __LINE__, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define clean_errno() (errno == 0 ? "None" : strerror(errno))
|
||||
|
||||
#define log_err(M, ...) fprintf(stderr,\
|
||||
"[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\
|
||||
clean_errno(), ##__VA_ARGS__)
|
||||
|
||||
#define log_warn(M, ...) fprintf(stderr,\
|
||||
"[WARN] (%s:%d: errno: %s) " M "\n",\
|
||||
__FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
|
||||
|
||||
#ifdef NOLOG
|
||||
#define log(M, ...)
|
||||
#define log_info(M, ...)
|
||||
#else
|
||||
#define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) =========>> " M "\n",\
|
||||
__FILE__, __LINE__, ##__VA_ARGS__)
|
||||
|
||||
#define log(M, ...) fprintf(stderr, "[INFO] %s (%lu:%s:%d) " M "\n",\
|
||||
nano_get_time(), pthread_self(), __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define check(A, M, ...) if(!(A)) {\
|
||||
log_err(M, ##__VA_ARGS__); errno=0; goto error; }
|
||||
|
||||
#define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\
|
||||
errno=0; goto error; }
|
||||
|
||||
#define check_mem(A) check((A), "Out of memory.")
|
||||
|
||||
#define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\
|
||||
errno=0; goto error; }
|
||||
|
||||
#endif
|
45
nanolib/include/hash.h
Normal file
45
nanolib/include/hash.h
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef HASH_H
|
||||
#define HASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
struct topic_queue {
|
||||
char *topic;
|
||||
struct topic_queue *next;
|
||||
};
|
||||
|
||||
void push_val(int key, char *val);
|
||||
|
||||
char *get_val(int key);
|
||||
|
||||
void del_val(int key);
|
||||
|
||||
void add_topic(char *id, char *val);
|
||||
|
||||
struct topic_queue *get_topic(char *id);
|
||||
|
||||
void del_topic_one(char *id, char *topic);
|
||||
|
||||
void del_topic_all(char *id);
|
||||
|
||||
bool check_id(char *id);
|
||||
|
||||
|
||||
void add_pipe_id(uint32_t pipe_id, char *client_id);
|
||||
|
||||
void del_pipe_id(uint32_t pipe_id);
|
||||
|
||||
char *get_client_id(uint32_t pipe_id);
|
||||
|
||||
bool check_pipe_id(uint32_t pipe_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
131
nanolib/include/mqtt_db.h
Normal file
131
nanolib/include/mqtt_db.h
Normal file
@ -0,0 +1,131 @@
|
||||
#ifndef MQTT_DB_H
|
||||
#define MQTT_DB_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum {UNEQUAL = 0, EQUAL = 1 } state;
|
||||
|
||||
struct client {
|
||||
char *id;
|
||||
void *ctxt;
|
||||
struct client *next;
|
||||
};
|
||||
|
||||
struct clients {
|
||||
struct client* sub_client;
|
||||
struct clients* down;
|
||||
int len;
|
||||
};
|
||||
|
||||
|
||||
struct retain_msg {
|
||||
uint8_t qos;
|
||||
bool exist;
|
||||
void *message;
|
||||
};
|
||||
|
||||
struct db_node {
|
||||
char *topic;
|
||||
bool hashtag;
|
||||
bool plus;
|
||||
struct retain_msg *retain;
|
||||
struct client *sub_client;
|
||||
struct db_node *up;
|
||||
struct db_node *down;
|
||||
struct db_node *next;
|
||||
};
|
||||
|
||||
/*
|
||||
** for print_db_tree
|
||||
*/
|
||||
|
||||
struct db_nodes {
|
||||
struct db_node *node;
|
||||
struct db_nodes *next;
|
||||
};
|
||||
|
||||
/* if topic equal NULL, topic is finded */
|
||||
struct topic_and_node {
|
||||
char **topic;
|
||||
bool hashtag;
|
||||
struct db_node *node;
|
||||
state t_state;
|
||||
};
|
||||
|
||||
struct db_tree{
|
||||
struct db_node *root;
|
||||
// TODO
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Create a db_tree */
|
||||
void create_db_tree(struct db_tree **db);
|
||||
|
||||
/* Delete a db_tree */
|
||||
void destory_db_tree(struct db_tree *db);
|
||||
|
||||
void print_db_tree(struct db_tree *db);
|
||||
|
||||
bool check_hashtag(char *topic_data);
|
||||
|
||||
bool check_plus(char *topic_data);
|
||||
|
||||
struct db_node *new_db_node(char *topic);
|
||||
|
||||
void delete_db_node(struct db_node *node);
|
||||
|
||||
void set_db_node(struct db_node *node, char **topic_queue);
|
||||
|
||||
/* Search node in db_tree*/
|
||||
void search_node(struct db_tree *db, char **topic_queue, struct topic_and_node *tan);
|
||||
|
||||
/* Add node to db_tree */
|
||||
void add_node(struct topic_and_node *input, struct client *id);
|
||||
|
||||
/* Delete node from db_tree when node does not have clientId */
|
||||
void del_node(struct db_node *node);
|
||||
|
||||
void del_all(uint32_t pipe_id, void *db);
|
||||
|
||||
/* Free node memory */
|
||||
void free_node(struct db_node *node);
|
||||
|
||||
/* Parsing topic from char* with '/' to char** */
|
||||
char **topic_parse(char *topic);
|
||||
|
||||
struct db_node *find_next(struct db_node *node, bool *equal, char
|
||||
**topic_queue);
|
||||
|
||||
void set_retain_msg(struct db_node *node, struct retain_msg *retain);
|
||||
|
||||
struct retain_msg *get_retain_msg(struct db_node *node);
|
||||
|
||||
struct clients *search_client(struct db_node *root, char **topic_queue);
|
||||
|
||||
bool check_client(struct db_node *node, char *id);
|
||||
|
||||
/* Delete client id. */
|
||||
struct client *del_client(struct topic_and_node *input, char *id);
|
||||
|
||||
struct client *set_client(const char *id, void *ctxt);
|
||||
|
||||
void set_topic_and_node(char **topic_queue, bool hashtag, state t_state,
|
||||
struct db_node *node, struct topic_and_node *tan);
|
||||
|
||||
struct client **iterate_client(struct clients * sub_clients, int *cols);
|
||||
|
||||
struct clients *new_clients(struct client *sub_client);
|
||||
|
||||
/* Add client id. */
|
||||
void add_client(struct topic_and_node *input, struct client* sub_client);
|
||||
|
||||
/* A hash table, clientId or alias as key, topic as value */
|
||||
char* hash_check_alias(int alias);
|
||||
|
||||
void hash_add_alias(int alias, char *topic_data);
|
||||
|
||||
void hash_del_alias(int alias);
|
||||
|
||||
#endif
|
17
nanolib/include/nanolib.h
Normal file
17
nanolib/include/nanolib.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef NANOLIB_H
|
||||
#define NANOLIB_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include "mqtt_db.h"
|
||||
#include "zmalloc.h"
|
||||
#include "hash.h"
|
||||
#include "dbg.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
41
nanolib/include/zmalloc.h
Normal file
41
nanolib/include/zmalloc.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* zmalloc - total amount of allocated memory aware version of malloc()
|
||||
*
|
||||
* Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __ZMALLOC_H
|
||||
#define __ZMALLOC_H
|
||||
#include <stddef.h>
|
||||
|
||||
void *zmalloc(size_t size);
|
||||
void *zrealloc(void *ptr, size_t size);
|
||||
void zfree(void *ptr);
|
||||
char *zstrdup(const char *s);
|
||||
size_t zmalloc_used_memory(void);
|
||||
|
||||
#endif /* _ZMALLOC_H */
|
944
nanolib/mqtt_db.c
Normal file
944
nanolib/mqtt_db.c
Normal file
@ -0,0 +1,944 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "include/mqtt_db.h"
|
||||
#include "include/zmalloc.h"
|
||||
#include "include/hash.h"
|
||||
#include "include/dbg.h"
|
||||
|
||||
|
||||
/*
|
||||
** Create a db_tree
|
||||
** Declare a global variable as func para
|
||||
** struct db_tree *db;
|
||||
*/
|
||||
void create_db_tree(struct db_tree **db)
|
||||
{
|
||||
log_info("CREATE_DB_TREE");
|
||||
*db = (struct db_tree *)zmalloc(sizeof(struct db_tree));
|
||||
memset(*db, 0, sizeof(struct db_tree));
|
||||
|
||||
struct db_node *node = new_db_node("\0");
|
||||
(*db)->root = node;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Destory db tree
|
||||
** destory all node & db_tree
|
||||
*/
|
||||
void destory_db_tree(struct db_tree *db)
|
||||
{
|
||||
log_info("DESTORY_DB_TREE");
|
||||
/* TODO */
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
** Print db_tree
|
||||
** For debugging, you can output all node
|
||||
** & node info
|
||||
*/
|
||||
#ifdef NOLOG
|
||||
void print_db_tree(struct db_tree *db)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#else
|
||||
void print_db_tree(struct db_tree *db)
|
||||
{
|
||||
assert(db);
|
||||
struct db_nodes *tmps = NULL;
|
||||
struct db_nodes *tmps_end = NULL;
|
||||
tmps = (struct db_nodes*)zmalloc(sizeof(struct db_nodes));
|
||||
tmps->node = db->root;
|
||||
int size = 1;
|
||||
int len = size;
|
||||
tmps->next = NULL;
|
||||
tmps_end = tmps;
|
||||
|
||||
puts("-------------------DB_TREE---------------------");
|
||||
puts("TOPIC | HASHTAG&PLUS | CLIENTID | FATHER_NODE");
|
||||
puts("-----------------------------------------------");
|
||||
|
||||
while (tmps) {
|
||||
size = 0;
|
||||
while (len-- && tmps) {
|
||||
struct db_node *tmp = tmps->node;
|
||||
while (tmp) {
|
||||
printf("\"%s\" ", tmp->topic);
|
||||
printf("%d", tmp->hashtag);
|
||||
printf("%d ", tmp->plus);
|
||||
if (tmp->sub_client) {
|
||||
printf("%s ", tmp->sub_client->id);
|
||||
if (tmp->sub_client->next) {
|
||||
printf("and more ");
|
||||
} else {
|
||||
printf("no more ");
|
||||
}
|
||||
|
||||
} else {
|
||||
printf("-- ");
|
||||
}
|
||||
if (tmp->up) {
|
||||
if (strcmp("#", tmp->topic)) {
|
||||
printf("\"%s\"\t ", tmp->up->topic);
|
||||
} else {
|
||||
printf("<-\t ");
|
||||
}
|
||||
|
||||
} else {
|
||||
printf("--\t");
|
||||
}
|
||||
|
||||
if (tmp->down) {
|
||||
// debug("sth new");
|
||||
size++;
|
||||
tmps_end->next = (struct db_nodes*)zmalloc(sizeof(struct db_nodes));
|
||||
tmps_end = tmps_end->next;
|
||||
tmps_end->node = tmp->down;
|
||||
tmps_end->next = NULL;
|
||||
}
|
||||
if (tmp) {
|
||||
// debug("tmp next");
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
// debug("tmps next");
|
||||
tmps = tmps->next;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
if (size == 0) {
|
||||
break;
|
||||
}
|
||||
puts("----------------------------------------------");
|
||||
|
||||
len = size;
|
||||
|
||||
}
|
||||
|
||||
puts("-------------------DB_TREE---------------------\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Determine if the current topic data is "#"
|
||||
** or not.
|
||||
*/
|
||||
bool check_hashtag(char *topic_data)
|
||||
{
|
||||
if (topic_data == NULL) {
|
||||
return false;
|
||||
}
|
||||
return !strcmp(topic_data, "#");
|
||||
}
|
||||
|
||||
/*
|
||||
** Determine if the current topic data is "+"
|
||||
** or not.
|
||||
*/
|
||||
bool check_plus(char *topic_data)
|
||||
{
|
||||
if (topic_data == NULL) {
|
||||
return false;
|
||||
}
|
||||
return !strcmp(topic_data, "+");
|
||||
}
|
||||
|
||||
struct db_node *new_db_node(char *topic)
|
||||
{
|
||||
struct db_node *node = NULL;
|
||||
node = (struct db_node*)zmalloc(sizeof(struct db_node));
|
||||
node->topic = (char*)zmalloc(strlen(topic)+1);
|
||||
memcpy(node->topic, topic, strlen(topic)+1);
|
||||
log("new_db_node %s", node->topic);
|
||||
node->hashtag = false;
|
||||
node->plus = false;
|
||||
node->next = NULL;
|
||||
node->down = NULL;
|
||||
node->up = NULL;
|
||||
node->sub_client = NULL;
|
||||
return node;
|
||||
}
|
||||
|
||||
void delete_db_node(struct db_node *node)
|
||||
{
|
||||
if (node) {
|
||||
log("delete_db_node %s", node->topic);
|
||||
if (node->topic) {
|
||||
zfree(node->topic);
|
||||
}
|
||||
node->topic = NULL;
|
||||
node->up = NULL;
|
||||
node->next = NULL;
|
||||
node->down = NULL;
|
||||
zfree(node);
|
||||
}
|
||||
node = NULL;
|
||||
}
|
||||
|
||||
void set_db_node(struct db_node *node, char **topic_queue)
|
||||
{
|
||||
if (node) {
|
||||
debug("set_db_node topic is %s", *topic_queue);
|
||||
node->down = new_db_node(*(topic_queue));
|
||||
node->down->up = node;
|
||||
node->down->next = NULL;
|
||||
node->down->down = NULL;
|
||||
} else {
|
||||
/* TODO */
|
||||
}
|
||||
}
|
||||
|
||||
void insert_db_node(struct db_node *new_node, struct db_node *old_node)
|
||||
{
|
||||
log("insert_db_node %s", new_node->topic);
|
||||
if (old_node->next != new_node) {
|
||||
struct db_node *tmp_node = NULL;
|
||||
tmp_node = old_node->next;
|
||||
old_node->next = new_node;
|
||||
new_node->next = tmp_node->next;
|
||||
}
|
||||
new_node->up = old_node->up ? old_node->up : old_node;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add nodes when the sub node is not found in the tree.
|
||||
** You need do serach_node and set client before add_node.
|
||||
** input is the result of search_node, id is the result
|
||||
** of set_client.
|
||||
*/
|
||||
void add_node(struct topic_and_node *input, struct client *id)
|
||||
{
|
||||
log_info("ADD_NODE_START");
|
||||
assert(input);
|
||||
struct db_node *tmp_node = NULL;
|
||||
struct db_node *new_node = NULL;
|
||||
char **topic_queue = input->topic;
|
||||
|
||||
if (topic_queue == NULL) {
|
||||
log("Topic_queue is NULL, no topic is needed add!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (input->t_state == EQUAL) {
|
||||
/*
|
||||
** # is the last string in topic
|
||||
*/
|
||||
if (input->hashtag) {
|
||||
input->node->hashtag = true;
|
||||
if (input->node->next) {
|
||||
new_node = new_db_node(*(++topic_queue));
|
||||
insert_db_node(new_node, input->node);
|
||||
} else {
|
||||
input->node->next = new_db_node(*(++topic_queue));
|
||||
insert_db_node(input->node->next, input->node);
|
||||
new_node = input->node->next;
|
||||
}
|
||||
|
||||
} else {
|
||||
set_db_node(input->node, ++topic_queue);
|
||||
if (check_plus(*(topic_queue))) {
|
||||
debug("equal, plus is true");
|
||||
input->node->plus = true;
|
||||
}
|
||||
new_node = input->node->down;
|
||||
}
|
||||
|
||||
} else {
|
||||
new_node = new_db_node(*topic_queue);
|
||||
new_node->up = input->node;
|
||||
|
||||
if (check_plus(*topic_queue)) {
|
||||
debug("unequal, plus is true");
|
||||
input->node->plus = true;
|
||||
tmp_node = input->node->down;
|
||||
input->node->down = new_node;
|
||||
new_node->next = tmp_node;
|
||||
} else {
|
||||
debug("unequal, plus is not true");
|
||||
if (input->node->down->next) {
|
||||
if (input->node->down->hashtag) {
|
||||
tmp_node = input->node->down->next->next;
|
||||
input->node->down->next->next = new_node;
|
||||
new_node->next = tmp_node;
|
||||
|
||||
} else {
|
||||
tmp_node = input->node->down->next;
|
||||
input->node->down->next = new_node;
|
||||
new_node->next = tmp_node;
|
||||
}
|
||||
} else {
|
||||
input->node->down->next = new_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (*(++topic_queue)) {
|
||||
if (check_hashtag(*topic_queue)) {
|
||||
debug("set hashtag is true");
|
||||
new_node->hashtag = true;
|
||||
/*
|
||||
** TODO delete it or not
|
||||
*/
|
||||
if (new_node->next) {
|
||||
tmp_node = new_db_node(*topic_queue);
|
||||
tmp_node->up = new_node->up ? new_node->up : NULL;
|
||||
tmp_node->down = NULL;
|
||||
tmp_node->next = new_node->next;
|
||||
new_node->next = tmp_node;
|
||||
|
||||
} else {
|
||||
new_node->next = new_db_node(*topic_queue);
|
||||
insert_db_node(new_node->next, new_node);
|
||||
}
|
||||
new_node = new_node->next;
|
||||
} else {
|
||||
if (check_plus(*topic_queue)) {
|
||||
new_node->plus = true;
|
||||
}
|
||||
set_db_node(new_node, topic_queue);
|
||||
new_node = new_node->down;
|
||||
}
|
||||
}
|
||||
|
||||
input->node = new_node;
|
||||
|
||||
if (id) {
|
||||
new_node->sub_client = id;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* For duplicate node
|
||||
TODO*/
|
||||
void del_node(struct db_node *node)
|
||||
{
|
||||
assert(node);
|
||||
log_info("DEL_NODE_START");
|
||||
if (node->sub_client || node->down || node->hashtag) {
|
||||
log("Node can't be deleted!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (node->next) {
|
||||
log("DELETE NODE AND NEXT!");
|
||||
struct db_node *first = node->up->down;
|
||||
if (first == node) {
|
||||
node->up->plus = false;
|
||||
node->up->down = node->next ? node->next : NULL;
|
||||
} else {
|
||||
while (first->next != node) {
|
||||
first = first->next;
|
||||
}
|
||||
if (first->hashtag) {
|
||||
first->hashtag = false;
|
||||
first->next = first->next->next;
|
||||
del_node(first);
|
||||
} else {
|
||||
first->next = first->next->next;
|
||||
}
|
||||
}
|
||||
/* delete node */
|
||||
delete_db_node(node);
|
||||
} else {
|
||||
log("DELETE NODE AND UP!");
|
||||
if (node->up == NULL) {
|
||||
log("Node can't be deleted!");
|
||||
return;
|
||||
} else if (node->up->next == node) {
|
||||
node->up->hashtag = false;
|
||||
node->up->next = NULL;
|
||||
delete_db_node(node);
|
||||
return;
|
||||
}
|
||||
|
||||
struct db_node *tmp_node = node->up;
|
||||
if (tmp_node->plus && tmp_node->down == node) {
|
||||
tmp_node->plus = false;
|
||||
}
|
||||
|
||||
if (tmp_node->down == node) {
|
||||
tmp_node->down = NULL;
|
||||
} else {
|
||||
tmp_node = tmp_node->down;
|
||||
while (tmp_node->next != node) {
|
||||
tmp_node = tmp_node->next;
|
||||
}
|
||||
if (tmp_node->hashtag) {
|
||||
tmp_node->hashtag = false;
|
||||
tmp_node->next = tmp_node->next->next;
|
||||
} else {
|
||||
tmp_node->next = tmp_node->next->next;
|
||||
}
|
||||
}
|
||||
delete_db_node(node);
|
||||
/* delete node */
|
||||
del_node(tmp_node);
|
||||
|
||||
/* iter */
|
||||
/*
|
||||
while (1) {
|
||||
// TODO
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void set_retain_msg(struct db_node *node, struct retain_msg *retain)
|
||||
{
|
||||
node->retain = retain;
|
||||
}
|
||||
|
||||
struct retain_msg *get_retain_msg(struct db_node *node)
|
||||
{
|
||||
return node->retain;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete client.
|
||||
*/
|
||||
struct client *del_client(struct topic_and_node *input, char *id)
|
||||
{
|
||||
log_info("DEL_CLIENT_START");
|
||||
assert(input && id);
|
||||
struct client *client = input->node->sub_client;
|
||||
struct client *before_client = NULL;
|
||||
while (client) {
|
||||
// debug("delete id is %s, client id is %s", id, client->id);
|
||||
if (!strcmp(client->id, id)) {
|
||||
log("delete client %s", id);
|
||||
if (before_client) {
|
||||
before_client->next = before_client->next->next;
|
||||
return client;
|
||||
} else {
|
||||
before_client = input->node->sub_client;
|
||||
if (input->node->sub_client->next) {
|
||||
input->node->sub_client = input->node->sub_client->next;
|
||||
} else {
|
||||
input->node->sub_client = NULL;
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
}
|
||||
before_client = client;
|
||||
client = client->next;
|
||||
}
|
||||
if (client == NULL) {
|
||||
log("no client is deleted!");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool check_client(struct db_node *node, char *id)
|
||||
{
|
||||
assert(node && id);
|
||||
struct client *sub = node->sub_client;
|
||||
while (sub) {
|
||||
if(!strcmp(sub->id, id)) {
|
||||
log("clientID you find is in the tree node");
|
||||
return false;
|
||||
}
|
||||
|
||||
sub = sub->next;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
struct client *set_client(const char *id, void *ctxt)
|
||||
{
|
||||
assert(id);
|
||||
// assert(ctxt);
|
||||
struct client *sub_client = NULL;
|
||||
sub_client = (struct client*)zmalloc(sizeof(struct client));
|
||||
memset(sub_client, 0, sizeof(struct client));
|
||||
sub_client->id = (char*)zmalloc(strlen(id)+1);
|
||||
memcpy(sub_client->id, id, strlen(id)+1);
|
||||
sub_client->ctxt = ctxt;
|
||||
// sub_client->next = NULL;
|
||||
return sub_client;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
** Add client.
|
||||
** Before add_client, you can call set_client to set the val of client
|
||||
** & search_node to get the val of res where you can add_client
|
||||
*/
|
||||
void add_client(struct topic_and_node *input, struct client *sub_client)
|
||||
{
|
||||
log_info("ADD_CLIENT_START");
|
||||
assert(input && sub_client);
|
||||
|
||||
if (input->node->sub_client == NULL) {
|
||||
input->node->sub_client = sub_client;
|
||||
log("add first client in this node");
|
||||
} else {
|
||||
struct client *client = input->node->sub_client;
|
||||
if (!strcmp(client->id, sub_client->id)) {
|
||||
log("clientID you find is in the tree node");
|
||||
return;
|
||||
}
|
||||
|
||||
while (client->next) {
|
||||
if (strcmp(client->id, sub_client->id)) {
|
||||
client = client->next;
|
||||
} else {
|
||||
log("clientID you find is in the tree node");
|
||||
return;
|
||||
}
|
||||
}
|
||||
log("add client %s", sub_client->id);
|
||||
client->next = sub_client;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void set_topic_and_node(char **topic_queue, bool hashtag, state t_state,
|
||||
struct db_node *node, struct topic_and_node *tan)
|
||||
{
|
||||
tan->t_state = t_state;
|
||||
tan->topic = topic_queue;
|
||||
tan->hashtag = hashtag;
|
||||
tan->node = node;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** search_node
|
||||
** Pass the parameters db_tree and topic_queue, you will get the
|
||||
** last node equal topic, if topic_queue matches exactly, tan->topic
|
||||
** will be set NULL.
|
||||
*/
|
||||
|
||||
void search_node(struct db_tree *db, char **topic_queue, struct topic_and_node *tan)
|
||||
{
|
||||
log_info("SEARCH_NODE_START");
|
||||
assert(db->root && topic_queue);
|
||||
struct db_node *node = db->root;
|
||||
|
||||
while (*topic_queue && node){
|
||||
log("topic is: %s, node->topic is: %s", *topic_queue, node->topic);
|
||||
if (strcmp(node->topic, *topic_queue)) {
|
||||
bool equal = false;
|
||||
node = find_next(node, &equal, topic_queue);
|
||||
if (equal == false) {
|
||||
log("searching unqual");
|
||||
set_topic_and_node(topic_queue, false, UNEQUAL, node->up, tan);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (node->hashtag && check_hashtag(*(topic_queue+1))) {
|
||||
log("searching # with hashtag");
|
||||
set_topic_and_node(NULL, true, EQUAL, node->next, tan);
|
||||
debug("%s", node->next->sub_client->id);
|
||||
break;
|
||||
} else if (check_hashtag(*(topic_queue+1))) {
|
||||
log("searching # no hashtag");
|
||||
set_topic_and_node(topic_queue, true, EQUAL, node, tan);
|
||||
break;
|
||||
}
|
||||
|
||||
log("searching no hashtag");
|
||||
if (node->down && *(topic_queue+1)) {
|
||||
// debug("continue");
|
||||
topic_queue++;
|
||||
node = node->down;
|
||||
} else if (*(topic_queue+1) == NULL) {
|
||||
// debug("topic_queue is NULL");
|
||||
set_topic_and_node(NULL, false, EQUAL, node, tan);
|
||||
// debug("node->topic = %s", node->topic);
|
||||
break;
|
||||
} else {
|
||||
// debug("node is NULL");
|
||||
set_topic_and_node(topic_queue, false, EQUAL, node, tan);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void del_all(uint32_t pipe_id, void *ptr)
|
||||
{
|
||||
char *client = get_client_id(pipe_id);
|
||||
if (client == NULL) {
|
||||
log("no client is found");
|
||||
return;
|
||||
}
|
||||
log("--PID %d--CLID %s--", pipe_id, client);
|
||||
struct db_tree *db = ptr;
|
||||
|
||||
if (client) {
|
||||
if (check_id(client)) {
|
||||
struct topic_queue *tq = get_topic(client);
|
||||
while (tq) {
|
||||
char **topic_queue = topic_parse(tq->topic);
|
||||
struct topic_and_node *tan = NULL;
|
||||
tan = (struct topic_and_node*)zmalloc(sizeof(struct topic_and_node));
|
||||
search_node(db, topic_queue, tan);
|
||||
debug("%s", tan->node->topic);
|
||||
del_client(tan, client);
|
||||
// struct client * cli = del_client(tan, client);
|
||||
// TODO free cli
|
||||
// cli = NULL;
|
||||
del_node(tan->node);
|
||||
|
||||
char *tmp = NULL;
|
||||
char **tt = topic_queue;
|
||||
|
||||
while (*topic_queue) {
|
||||
tmp = *topic_queue;
|
||||
topic_queue++;
|
||||
zfree(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
|
||||
zfree(tt);
|
||||
topic_queue = NULL;
|
||||
|
||||
zfree(tan);
|
||||
tan = NULL;
|
||||
|
||||
tq = tq->next;
|
||||
}
|
||||
del_topic_all(client);
|
||||
del_pipe_id(pipe_id);
|
||||
log("del all");
|
||||
} else {
|
||||
log("no topic can be found");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void *get_client_info(struct db_node *node)
|
||||
{
|
||||
/* TODO */
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
struct client **iterate_client(struct clients *sub_clients, int *cols)
|
||||
{
|
||||
|
||||
*cols = 1;
|
||||
struct client **client_queue = NULL;
|
||||
|
||||
while (sub_clients) {
|
||||
struct client *sub_client = sub_clients->sub_client;
|
||||
while (sub_client) {
|
||||
bool equal = false;
|
||||
client_queue = (struct client**)zrealloc(client_queue, (*cols)*sizeof(struct client*));
|
||||
|
||||
for (int i = 0; i < (*cols)-1; i++) {
|
||||
if (!strcmp(sub_client->id, client_queue[i]->id)) {
|
||||
equal = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (equal == false) {
|
||||
client_queue[(*cols)-1] = sub_client;
|
||||
(*cols)++;
|
||||
}
|
||||
sub_client = sub_client->next;
|
||||
}
|
||||
sub_clients = sub_clients->down;
|
||||
}
|
||||
|
||||
client_queue = (struct client**)zrealloc(client_queue, (*cols) * sizeof(struct client*));
|
||||
client_queue[(*cols)-1] = NULL;
|
||||
return client_queue;
|
||||
}
|
||||
|
||||
struct clients *new_clients(struct client *sub_client)
|
||||
{
|
||||
struct clients *sub_clients = NULL;
|
||||
if (sub_client) {
|
||||
sub_clients = (struct clients*)zmalloc(sizeof(struct clients));
|
||||
sub_clients->sub_client = sub_client;
|
||||
sub_clients->down = NULL;
|
||||
debug("first client is %s", sub_clients->sub_client->id);
|
||||
}
|
||||
return sub_clients;
|
||||
}
|
||||
|
||||
struct db_node *find_next(struct db_node *node, bool *equal, char **topic_queue)
|
||||
{
|
||||
struct db_node *t = node;
|
||||
|
||||
if (node == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (t->next) {
|
||||
t = t->next;
|
||||
log("t->topic %s, topic_queue %s", t->topic,
|
||||
*(topic_queue));
|
||||
if (!strcmp(t->topic, *(topic_queue))) {
|
||||
*equal = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** search_client
|
||||
** When you use this func, the parameters you need to pass are the root
|
||||
** node of the tree and the complete topic_queue. You will get all the
|
||||
** subscribers to this topic.
|
||||
*/
|
||||
struct clients *search_client(struct db_node *root, char **topic_queue)
|
||||
{
|
||||
log_info("SEARCH_CLIENT_START");
|
||||
assert(root && topic_queue);
|
||||
struct clients *res = NULL;
|
||||
struct clients *tmp = NULL;
|
||||
tmp = (struct clients*)zmalloc(sizeof(struct clients));
|
||||
memset(tmp, 0, sizeof(struct clients));
|
||||
res = tmp;
|
||||
struct db_node *node = root;
|
||||
|
||||
log("entry search");
|
||||
while (*topic_queue && node) {
|
||||
if (strcmp(node->topic, *topic_queue)) {
|
||||
log("node->topic %s, topic_queue %s", node->topic, *topic_queue);
|
||||
|
||||
bool plus = false;
|
||||
if (!strcmp(node->topic, "+")) {
|
||||
if (*(topic_queue+1) == NULL) {
|
||||
if (node->sub_client) {
|
||||
log("add client in last +");
|
||||
tmp->down = new_clients(node->sub_client);
|
||||
tmp = tmp->down;
|
||||
}
|
||||
} else {
|
||||
plus = true;
|
||||
if (node->hashtag) {
|
||||
log("Find the sign of #. Add it if sub_client is exist");
|
||||
if (node->next->sub_client) {
|
||||
tmp->down = new_clients(node->next->sub_client);
|
||||
tmp = tmp->down;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool equal = false;
|
||||
node = find_next(node, &equal, topic_queue);
|
||||
|
||||
if (equal == false && plus == false) {
|
||||
log("searching unqual");
|
||||
return res;
|
||||
}
|
||||
|
||||
if (equal == false && plus == true) {
|
||||
node = node->up->down;
|
||||
}
|
||||
}
|
||||
|
||||
if (node->hashtag) {
|
||||
log("Find the sign of #. Add it if sub_client of # is exist!");
|
||||
if (node->next->sub_client) {
|
||||
tmp->down = new_clients(node->next->sub_client);
|
||||
tmp = tmp->down;
|
||||
}
|
||||
}
|
||||
|
||||
if (*(topic_queue+1) == NULL) {
|
||||
log("Current node is the last one. Add it if sub_client is exist!");
|
||||
tmp->down = new_clients(node->sub_client);
|
||||
tmp = tmp->down;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
if (node->plus) {
|
||||
log("Find the sign of +");
|
||||
if (*(topic_queue+2) == NULL) {
|
||||
debug("When plus is the last one");
|
||||
if (node->down->hashtag) {
|
||||
log("Find the sign of #. Add it if sub_client of # is exist!");
|
||||
if (node->down->next->sub_client) {
|
||||
tmp->down = new_clients(node->down->next->sub_client);
|
||||
tmp = tmp->down;
|
||||
}
|
||||
}
|
||||
|
||||
if (node->down->sub_client) {
|
||||
tmp->down = new_clients(node->down->sub_client);
|
||||
tmp = tmp->down;
|
||||
}
|
||||
|
||||
bool equal = false;
|
||||
struct db_node *t = find_next(node->down, &equal,
|
||||
++topic_queue);
|
||||
|
||||
if (equal == false) {
|
||||
log("searching unqual");
|
||||
return res;
|
||||
}
|
||||
|
||||
if (t->hashtag) {
|
||||
log("Find the sign of #. Add it if sub_client of # is exist!");
|
||||
if (t->next->sub_client) {
|
||||
tmp->down = new_clients(t->next->sub_client);
|
||||
tmp = tmp->down;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (t->sub_client) {
|
||||
tmp->down = new_clients(t->sub_client);
|
||||
tmp = tmp->down;
|
||||
}
|
||||
return res;
|
||||
|
||||
} else if (node->down->down == NULL) {
|
||||
log("topic is longer than tree, check hashtag");
|
||||
|
||||
if (node->down->hashtag) {
|
||||
log("Find the sign of #. Add it if sub_client of # is exist!");
|
||||
if (node->down->next->sub_client) {
|
||||
tmp->down = new_clients(node->down->next->sub_client);
|
||||
tmp = tmp->down;
|
||||
}
|
||||
}
|
||||
|
||||
bool equal = false;
|
||||
struct db_node *t = find_next(node->down, &equal,
|
||||
++topic_queue);
|
||||
|
||||
if (equal == false) {
|
||||
log("searching unqual");
|
||||
return res;
|
||||
}
|
||||
|
||||
if (t->hashtag) {
|
||||
log("Find the sign of #. Add it if sub_client of # is exist!");
|
||||
if (t->next->sub_client) {
|
||||
tmp->down = new_clients(t->next->sub_client);
|
||||
tmp = tmp->down;
|
||||
}
|
||||
}
|
||||
|
||||
if (t != node->down) {
|
||||
log("t->topic, %s, topic_queue ,%s", t->topic,
|
||||
*(topic_queue));
|
||||
tmp->down = search_client(t, topic_queue);
|
||||
}
|
||||
return res;
|
||||
|
||||
} else if (node->down->down && *(topic_queue+2)) {
|
||||
log("continue");
|
||||
char ** tmp_topic = topic_queue;
|
||||
tmp->down = search_client(node->down, topic_queue+1);
|
||||
while (tmp->down) {
|
||||
tmp = tmp->down;
|
||||
}
|
||||
tmp->down = search_client(node->down->down, tmp_topic+2);
|
||||
return res;
|
||||
}
|
||||
|
||||
} else {
|
||||
log("Find node no sign of + & #");
|
||||
if (node->down && *(topic_queue+1)) {
|
||||
log("continue");
|
||||
topic_queue++;
|
||||
node = node->down;
|
||||
|
||||
} else {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* topic parsing */
|
||||
char **topic_parse(char *topic)
|
||||
{
|
||||
assert(topic != NULL);
|
||||
|
||||
int row = 1;
|
||||
int len = 2;
|
||||
char **topic_queue = NULL;
|
||||
char *before_pos = topic;
|
||||
char *pos = NULL;
|
||||
|
||||
if ((strncmp("$share", before_pos, 6) != 0 && strncmp("$SYS", before_pos, 4)
|
||||
!= 0)) {
|
||||
topic_queue = (char**)zmalloc(sizeof(char*)*row);
|
||||
topic_queue[row-1] = (char*)zmalloc(sizeof(char)*len);
|
||||
memcpy(topic_queue[row-1], "\0", (len));
|
||||
// strcpy(topic_queue[row-1], "");
|
||||
// topic_queue[0][0] = '';
|
||||
// topic_queue[row-1][len-1] = '\0';
|
||||
|
||||
}
|
||||
|
||||
while ((pos = strchr(before_pos, '/')) != NULL) {
|
||||
|
||||
if (topic_queue != NULL) {
|
||||
topic_queue = (char**)zrealloc(topic_queue, sizeof(char*)*(++row));
|
||||
} else {
|
||||
topic_queue = (char**)zmalloc(sizeof(char*)*row);
|
||||
}
|
||||
|
||||
|
||||
len = pos-before_pos+1;
|
||||
topic_queue[row-1] = (char*)zmalloc(sizeof(char)*len);
|
||||
memcpy(topic_queue[row-1], before_pos, (len-1));
|
||||
topic_queue[row-1][len-1] = '\0';
|
||||
before_pos = pos+1;
|
||||
}
|
||||
|
||||
len = strlen(before_pos);
|
||||
|
||||
if (topic_queue != NULL) {
|
||||
topic_queue = (char**)zrealloc(topic_queue, sizeof(char*)*(++row));
|
||||
} else {
|
||||
topic_queue = (char**)zmalloc(sizeof(char*)*row);
|
||||
}
|
||||
|
||||
topic_queue[row-1] = (char*)zmalloc(sizeof(char)*(len+1));
|
||||
// strcpy(topic_queue[row-1], before_pos);
|
||||
memcpy(topic_queue[row-1], before_pos, (len));
|
||||
topic_queue[row-1][len] = '\0';
|
||||
topic_queue = (char**)zrealloc(topic_queue, sizeof(char*)*(++row));
|
||||
topic_queue[row-1] = NULL;
|
||||
|
||||
return topic_queue;
|
||||
}
|
||||
|
||||
void hash_add_alias(int alias, char *topic_data)
|
||||
{
|
||||
assert(topic_data);
|
||||
push_val(alias, topic_data);
|
||||
}
|
||||
|
||||
char *hash_check_alias(int alias)
|
||||
{
|
||||
return get_val(alias);
|
||||
}
|
||||
|
||||
void hash_del_alias(int alias)
|
||||
{
|
||||
del_val(alias);
|
||||
}
|
||||
|
19
nanolib/packet_parser/Makefile
Normal file
19
nanolib/packet_parser/Makefile
Normal file
@ -0,0 +1,19 @@
|
||||
CC = gcc
|
||||
CFLAGS = -Wall
|
||||
DEPS = packet_parser.h
|
||||
OBJ = main.o packet_parser.o
|
||||
|
||||
|
||||
%.o:%.c $(DEPS)
|
||||
$(CC) -c -o $@ $< $(CFLAGS)
|
||||
|
||||
nanomqlib:$(OBJ)
|
||||
$(CC) -o nanolib $(OBJ)
|
||||
rm -f $(OBJ)
|
||||
|
||||
#$(CC) -o nanolib main.o packet_parser.o
|
||||
#$(CC) -o $@ $<
|
||||
|
||||
.PHONY:clean
|
||||
clean:
|
||||
rm -f $(OBJ) nanolib
|
7
nanolib/packet_parser/main.c
Normal file
7
nanolib/packet_parser/main.c
Normal file
@ -0,0 +1,7 @@
|
||||
#include "test.c"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
test();
|
||||
return 0;
|
||||
}
|
135
nanolib/packet_parser/packet_parser.c
Normal file
135
nanolib/packet_parser/packet_parser.c
Normal file
@ -0,0 +1,135 @@
|
||||
#include "packet_parser.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
uint8_t packet_parse_uint8(struct mqtt_packet *packet)
|
||||
{
|
||||
assert(packet && packet->remaining_length >= packet->pos+1);
|
||||
return packet->binary[packet->pos++];
|
||||
}
|
||||
|
||||
uint16_t packet_parse_uint16(struct mqtt_packet *packet)
|
||||
{
|
||||
assert(packet && packet->remaining_length >= packet->pos+2);
|
||||
uint16_t res = packet->binary[packet->pos++];
|
||||
return (res << 8) + packet->binary[packet->pos++];
|
||||
}
|
||||
|
||||
/* TODO judge endian */
|
||||
//uint16_t packet_parse_uint16(struct mqtt_packet *packet)
|
||||
//{
|
||||
// assert(packet && packet->remaining_length >= packet->pos+2);
|
||||
//
|
||||
// uint16_t res = 0;
|
||||
// memcpy((uint16_t*)&res, (uint16_t*)&(packet->binary[packet->pos]), sizeof(res));
|
||||
// printf("res is: %#X\n", res);
|
||||
// packet->pos+=2;
|
||||
// return res;
|
||||
//}
|
||||
|
||||
uint32_t packet_parse_uint32(struct mqtt_packet *packet)
|
||||
{
|
||||
assert(packet && packet->remaining_length >= packet->pos+4);
|
||||
uint32_t res = packet->binary[packet->pos++];
|
||||
|
||||
if (res) {
|
||||
while ((0xFF000000 & res) == 0) {
|
||||
res = (res << 8) + packet->binary[packet->pos++];
|
||||
}
|
||||
} else {
|
||||
int i = 4;
|
||||
while (--i > 0) {
|
||||
res = (res << 8) + packet->binary[packet->pos++];
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void packet_parse_string(struct mqtt_packet *packet, char str[], uint32_t length)
|
||||
{
|
||||
assert(packet && packet->remaining_length >= packet->pos+length);
|
||||
memcpy(str, &(packet->binary[packet->pos]), length);
|
||||
packet->pos += length;
|
||||
}
|
||||
|
||||
uint32_t packet_parse_var(struct mqtt_packet *packet)
|
||||
{
|
||||
assert(packet);
|
||||
int i = 4;
|
||||
uint32_t res = 0;
|
||||
uint32_t multiplier = 1;
|
||||
uint8_t byte;
|
||||
do {
|
||||
assert(packet->remaining_length >= packet->pos);
|
||||
|
||||
byte = packet->binary[packet->pos++];
|
||||
|
||||
res += (byte & 127) * multiplier;
|
||||
multiplier *= 128;
|
||||
} while (i-- && (byte & 128));
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
void packet_write_uint8(struct mqtt_packet *packet, uint8_t input)
|
||||
{
|
||||
assert(packet && packet->remaining_length >= packet->pos+1);
|
||||
packet->binary[packet->pos++] = input;
|
||||
}
|
||||
|
||||
void packet_write_uint16(struct mqtt_packet *packet, uint16_t input)
|
||||
{
|
||||
assert(packet && packet->remaining_length >= packet->pos+2);
|
||||
packet->binary[packet->pos++] = (input & 0xFF00) >> 8;
|
||||
packet->binary[packet->pos++] = input & 0x00FF;
|
||||
}
|
||||
|
||||
void packet_write_uint32(struct mqtt_packet *packet, uint32_t input)
|
||||
{
|
||||
assert(packet && packet->remaining_length >= packet->pos+4);
|
||||
packet->binary[packet->pos++] = (input & 0xFF000000) >> 24;
|
||||
packet->binary[packet->pos++] = (input & 0x00FF0000) >> 16;
|
||||
packet->binary[packet->pos++] = (input & 0x0000FF00) >> 8;
|
||||
packet->binary[packet->pos++] = (input & 0x000000FF);
|
||||
}
|
||||
|
||||
void packet_write_string(struct mqtt_packet *packet, char str[], uint32_t length)
|
||||
{
|
||||
assert(packet && packet->remaining_length >= packet->pos+length);
|
||||
memcpy(&(packet->binary[packet->pos]), str, length);
|
||||
packet->pos += length;
|
||||
}
|
||||
|
||||
void packet_write_var(struct mqtt_packet *packet, uint32_t input)
|
||||
{
|
||||
assert(packet);
|
||||
uint8_t byte;
|
||||
do {
|
||||
assert(packet->remaining_length >= packet->pos);
|
||||
/* Can be optimized */
|
||||
byte = input % 128;
|
||||
input /= 128;
|
||||
if (input > 0) {
|
||||
byte |= 128;
|
||||
}
|
||||
packet->binary[packet->pos++] = byte;
|
||||
|
||||
|
||||
} while (input);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
35
nanolib/packet_parser/packet_parser.h
Normal file
35
nanolib/packet_parser/packet_parser.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef PACKET_PAESER
|
||||
#define PACKET_PARSER
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short int uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef signed char int8_t;
|
||||
|
||||
|
||||
|
||||
struct mqtt_packet {
|
||||
uint8_t *binary;
|
||||
uint32_t pos;
|
||||
uint32_t remaining_length;
|
||||
};
|
||||
|
||||
|
||||
uint8_t packet_parse_uint8(struct mqtt_packet *packet);
|
||||
uint16_t packet_parse_uint16(struct mqtt_packet *packet);
|
||||
uint32_t packet_parse_uint32(struct mqtt_packet *packet);
|
||||
void packet_parse_string(struct mqtt_packet *packet, char str[], uint32_t length);
|
||||
uint32_t packet_parse_var(struct mqtt_packet *packet);
|
||||
|
||||
|
||||
void packet_write_uint8(struct mqtt_packet *packet, uint8_t input);
|
||||
void packet_write_uint16(struct mqtt_packet *packet, uint16_t input);
|
||||
void packet_write_uint32(struct mqtt_packet * packet, uint32_t intput);
|
||||
void packet_write_string(struct mqtt_packet *packet, char str[], uint32_t length);
|
||||
void packet_write_var(struct mqtt_packet *packet, uint32_t);
|
||||
|
||||
#endif
|
237
nanolib/packet_parser/test.c
Normal file
237
nanolib/packet_parser/test.c
Normal file
@ -0,0 +1,237 @@
|
||||
#include "packet_parser.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* =======================================================================
|
||||
* TEST
|
||||
* =======================================================================*/
|
||||
|
||||
static void uint8_write_read(uint8_t input, int remaining_length)
|
||||
{
|
||||
struct mqtt_packet packet;
|
||||
|
||||
memset(&packet, 0, sizeof(struct mqtt_packet));
|
||||
|
||||
packet.remaining_length = remaining_length;
|
||||
packet.binary = (uint8_t *)malloc(remaining_length*sizeof(uint8_t));
|
||||
packet_write_uint8(&packet, input);
|
||||
packet.pos = 0;
|
||||
|
||||
uint8_t res = packet_parse_uint8(&packet);
|
||||
if (input == res) {
|
||||
printf("Bingle, uint8 %#X is OK!\n", input);
|
||||
}
|
||||
free(packet.binary);
|
||||
packet.binary = NULL;
|
||||
|
||||
}
|
||||
|
||||
static void uint16_write_read(uint16_t input, uint32_t remaining_length)
|
||||
{
|
||||
struct mqtt_packet packet;
|
||||
memset(&packet, 0, sizeof(struct mqtt_packet));
|
||||
packet.remaining_length = remaining_length;
|
||||
packet.binary = (uint8_t *)malloc(remaining_length*sizeof(uint8_t));
|
||||
packet_write_uint16(&packet, input);
|
||||
packet.pos = 0;
|
||||
uint16_t res = packet_parse_uint16(&packet);
|
||||
if (input == res) {
|
||||
printf("Bingle, uint16 %#X is OK!\n", input);
|
||||
}
|
||||
|
||||
free(packet.binary);
|
||||
packet.binary = NULL;
|
||||
|
||||
}
|
||||
|
||||
static void uint32_write_read(uint32_t input, uint32_t remaining_length)
|
||||
{
|
||||
struct mqtt_packet packet;
|
||||
memset(&packet, 0, sizeof(struct mqtt_packet));
|
||||
packet.remaining_length = remaining_length;
|
||||
packet.binary = (uint8_t *)malloc(remaining_length*sizeof(uint8_t));
|
||||
packet_write_uint32(&packet, input);
|
||||
packet.pos = 0;
|
||||
|
||||
uint32_t res = packet_parse_uint32(&packet);
|
||||
if (input == res) {
|
||||
printf("Bingle, uint32 %#X is OK!\n", input);
|
||||
}
|
||||
free(packet.binary);
|
||||
packet.binary = NULL;
|
||||
|
||||
}
|
||||
|
||||
static void string_write_read(char *input, uint32_t remaining_length)
|
||||
{
|
||||
struct mqtt_packet packet;
|
||||
memset(&packet, 0, sizeof(struct mqtt_packet));
|
||||
packet.remaining_length = remaining_length;
|
||||
packet.binary = (char*)malloc(sizeof(char)*remaining_length);
|
||||
packet_write_string(&packet, input, remaining_length);
|
||||
|
||||
packet.pos = 0;
|
||||
char str[remaining_length];
|
||||
packet_parse_string(&packet, str, remaining_length);
|
||||
printf("\npacket_parse_string output: %s\n",
|
||||
str);
|
||||
|
||||
free(packet.binary);
|
||||
packet.binary = NULL;
|
||||
|
||||
}
|
||||
|
||||
static void var_write_read(uint32_t input, uint32_t remaining_length)
|
||||
{
|
||||
struct mqtt_packet packet;
|
||||
memset(&packet, 0, sizeof(packet));
|
||||
packet.remaining_length = remaining_length;
|
||||
packet.binary = (char*)malloc(sizeof(char)*remaining_length);
|
||||
packet_write_var(&packet, input);
|
||||
packet.pos = 0;
|
||||
|
||||
uint32_t res = packet_parse_var(&packet);
|
||||
if (res == input) {
|
||||
printf("Bingle, var length %#X is OK!\n", input);
|
||||
}
|
||||
|
||||
free(packet.binary);
|
||||
packet.binary = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void TEST_uint8_write_read(void)
|
||||
{
|
||||
/* Empty packet */
|
||||
// byte_write_read(NULL, 0);
|
||||
|
||||
uint8_t binary = 0;
|
||||
|
||||
/* 0 value */
|
||||
// memset(binary, 0, sizeof(binary));
|
||||
binary = 0x00;
|
||||
uint8_write_read(binary, 1);
|
||||
|
||||
|
||||
/* Middle */
|
||||
// memset(binary, 0, sizeof(binary));
|
||||
binary = 0x1F;
|
||||
uint8_write_read(binary, 1);
|
||||
|
||||
/* 255 value */
|
||||
// memset(binary, 0, sizeof(binary));
|
||||
binary = 0xFF;
|
||||
uint8_write_read(binary, 1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void TEST_uint16_write_read(void)
|
||||
{
|
||||
|
||||
/* Empty packet */
|
||||
// uint16_write_read(NULL, 0);
|
||||
uint16_t binary = 0;
|
||||
|
||||
/* 0 value */
|
||||
// memset(binary, 0, sizeof(binary));
|
||||
binary = 0x0000;
|
||||
uint16_write_read(binary, 2);
|
||||
|
||||
/* Endian check */
|
||||
// memset(binary, 0, sizeof(binary));
|
||||
binary = 0x38F3;
|
||||
uint16_write_read(binary, 2);
|
||||
|
||||
/* 65,535 value */
|
||||
// memset(binary, 0, sizeof(binary));
|
||||
binary = 0xFFFF;
|
||||
uint16_write_read(binary, 2);
|
||||
|
||||
}
|
||||
|
||||
static void TEST_uint32_write_read(void)
|
||||
{
|
||||
/* Empty packet */
|
||||
// uint32_write_read(NULL, 0);
|
||||
uint32_t binary = 0;
|
||||
|
||||
/* 0 value */
|
||||
binary = 0x00000000;
|
||||
uint32_write_read(binary, 4);
|
||||
|
||||
/* Endian check */
|
||||
binary = 0x12345678;
|
||||
uint32_write_read(binary, 4);
|
||||
|
||||
/* Biggest value */
|
||||
binary = 0xFFFFFFFF;
|
||||
uint32_write_read(binary, 4);
|
||||
|
||||
}
|
||||
|
||||
static void TEST_string_write_read(void)
|
||||
{
|
||||
// char *binary = "This is a string!";
|
||||
char binary[18];
|
||||
memset(binary, 0, sizeof(binary));
|
||||
binary[0] = 'T';
|
||||
binary[1] = 'h';
|
||||
binary[2] = 'i';
|
||||
binary[3] = 's';
|
||||
binary[4] = ' ';
|
||||
binary[5] = 'i';
|
||||
binary[6] = 's';
|
||||
binary[7] = ' ';
|
||||
binary[8] = 'a';
|
||||
binary[9] = ' ';
|
||||
binary[10] = 's';
|
||||
binary[11] = 't';
|
||||
binary[12] = 'r';
|
||||
binary[13] = 'i';
|
||||
binary[14] = 'n';
|
||||
binary[15] = 'g';
|
||||
binary[16] = '!';
|
||||
binary[17] = '\0';
|
||||
string_write_read(binary, 18);
|
||||
}
|
||||
|
||||
static void TEST_var_write_read(void)
|
||||
{
|
||||
uint32_t binary = 0;
|
||||
|
||||
/* 0 value */
|
||||
binary = 0x00000000;
|
||||
var_write_read(binary, 4);
|
||||
|
||||
/* Endian check */
|
||||
binary = 0x12;
|
||||
var_write_read(binary, 4);
|
||||
|
||||
/* Endian check */
|
||||
binary = 0x1234;
|
||||
var_write_read(binary, 4);
|
||||
/* Endian check */
|
||||
binary = 0x128456;
|
||||
var_write_read(binary, 4);
|
||||
/* Endian check */
|
||||
binary = 0x12348678;
|
||||
var_write_read(binary, 4);
|
||||
|
||||
/* Biggest value */
|
||||
binary = 0x7FFFFFFF;
|
||||
var_write_read(binary, 4);
|
||||
}
|
||||
|
||||
|
||||
void test(void)
|
||||
{
|
||||
TEST_uint8_write_read();
|
||||
TEST_uint16_write_read();
|
||||
TEST_uint32_write_read();
|
||||
TEST_string_write_read();
|
||||
TEST_var_write_read();
|
||||
}
|
402
nanolib/test.c
Normal file
402
nanolib/test.c
Normal file
@ -0,0 +1,402 @@
|
||||
#include <string.h>
|
||||
#include "include/nanolib.h"
|
||||
|
||||
|
||||
// struct clientId ID = {"150410"};
|
||||
// struct db_node node = {"", &ID, NULL, NULL, NULL, NULL, 1, -1};
|
||||
// struct db_tree db = {&node};
|
||||
|
||||
struct db_tree *db = NULL;
|
||||
|
||||
typedef enum{test_topic_parse = 0, test_search_node, test_add_node, test_del_node,
|
||||
test_hash_alias, test_topic_hash, test_pipe_hash} test_state;
|
||||
|
||||
struct client ID1 = {"150429", NULL, NULL};
|
||||
|
||||
static void Test_topic_parse(void)
|
||||
{
|
||||
puts(">>>>>>>>>> TEST_TOPIC_PARSE <<<<<<<<");
|
||||
// char *data = NULL;
|
||||
// char *data = "lee";
|
||||
// char *data = "$share/hom/jian";
|
||||
char *data = "$shar/hom/jian";
|
||||
printf("INPUT:%s\n", data);
|
||||
|
||||
char **res = topic_parse(data);
|
||||
char *t = NULL;
|
||||
char **tt = res;
|
||||
|
||||
|
||||
while (*res) {
|
||||
t = *res;
|
||||
printf("RES: %s\n", *res);
|
||||
res++;
|
||||
zfree(t);
|
||||
t = NULL;
|
||||
}
|
||||
|
||||
zfree(tt);
|
||||
res = NULL;
|
||||
}
|
||||
|
||||
static void Test_search_node(void)
|
||||
{
|
||||
puts(">>>>>>>>>> TEST_SEARCH_NODE <<<<<<<<");
|
||||
// char *data = "lee";
|
||||
char *data = "lee/hom/jian";
|
||||
|
||||
create_db_tree(&db);
|
||||
print_db_tree(db);
|
||||
struct topic_and_node *res = NULL;
|
||||
res = (struct topic_and_node*)zmalloc(sizeof(struct topic_and_node));
|
||||
char **topic_queue = topic_parse(data);
|
||||
search_node(db, topic_queue, res);
|
||||
|
||||
if (res->topic) {
|
||||
printf("RES_TOPIC: %s\n", *(res)->topic);
|
||||
}
|
||||
if (res->node) {
|
||||
printf("RES_NODE_STATE: %d\n", res->t_state);
|
||||
}
|
||||
if (res->node->sub_client) {
|
||||
printf("RES_NODE_UP_ID: %s\n", res->node->sub_client->id);
|
||||
}
|
||||
zfree(res);
|
||||
}
|
||||
|
||||
static void Test_add_node(void)
|
||||
{
|
||||
puts(">>>>>>>>>>> TEST_ADD_NODE <<<<<<<<<");
|
||||
char *data = "a/bv/cv";
|
||||
char *data1 = "a/b/c";
|
||||
char *data2 = "lee/+/+";
|
||||
char *data3 = "lee/hom/+";
|
||||
struct client ID3 = {"150410", NULL, NULL};
|
||||
struct client ID4 = {"150422", NULL, NULL};
|
||||
struct client ID5 = {"150418", NULL, NULL};
|
||||
|
||||
|
||||
struct topic_and_node *res = NULL;
|
||||
res = (struct topic_and_node*)zmalloc(sizeof(struct topic_and_node));
|
||||
char **topic_queue = topic_parse(data);
|
||||
|
||||
search_node(db, topic_queue, res);
|
||||
add_node(res, &ID1);
|
||||
print_db_tree(db);
|
||||
|
||||
search_node(db, topic_queue, res);
|
||||
add_node(res, &ID1);
|
||||
search_node(db, topic_queue, res);
|
||||
if (check_client(res->node, ID1.id)) {
|
||||
add_client(res, &ID1);
|
||||
} else {
|
||||
puts("2@@@@@@@@@@@@@@@@@@@@@@@@@@###@@@@@@@");
|
||||
}
|
||||
print_db_tree(db);
|
||||
printf("RES_NODE_ID: %s\n", res->node->sub_client->id);
|
||||
printf("RES_NODE_STATE: %d\n", res->t_state);
|
||||
if (res->topic) {
|
||||
printf("RES_TOPIC: %s\n", *(res->topic));
|
||||
}
|
||||
|
||||
topic_queue = topic_parse(data1);
|
||||
search_node(db, topic_queue, res);
|
||||
add_node(res, &ID3);
|
||||
print_db_tree(db);
|
||||
search_node(db, topic_queue, res);
|
||||
printf("RES_NODE_ID: %s\n", res->node->sub_client->id);
|
||||
printf("RES_NODE_STATE: %d\n", res->t_state);
|
||||
if (res->topic) {
|
||||
printf("RES_TOPIC: %s\n", *(res->topic));
|
||||
}
|
||||
|
||||
topic_queue = topic_parse(data2);
|
||||
search_node(db, topic_queue, res);
|
||||
add_node(res, &ID4);
|
||||
print_db_tree(db);
|
||||
|
||||
search_node(db, topic_queue, res);
|
||||
printf("RES_NODE_ID: %s\n", res->node->sub_client->id);
|
||||
printf("RES_NODE_STATE: %d\n", res->t_state);
|
||||
if (res->topic) {
|
||||
printf("RES_TOPIC: %s\n", *(res->topic));
|
||||
}
|
||||
|
||||
topic_queue = topic_parse(data3);
|
||||
search_node(db, topic_queue, res);
|
||||
if (res->topic) {
|
||||
add_node(res, &ID5);
|
||||
} else {
|
||||
if (check_client(res->node, ID5.id)) {
|
||||
add_client(res, &ID5);
|
||||
}
|
||||
}
|
||||
print_db_tree(db);
|
||||
|
||||
search_node(db, topic_queue, res);
|
||||
printf("RES_NODE_ID: %s\n", res->node->sub_client->id);
|
||||
printf("RES_NODE_STATE: %d\n", res->t_state);
|
||||
if (res->topic) {
|
||||
printf("RES_TOPIC: %s\n", *(res->topic));
|
||||
}
|
||||
}
|
||||
|
||||
static void Test_del_node(void)
|
||||
{
|
||||
puts(">>>>>>>>>> TEST_DEL_NODE <<<<<<<<");
|
||||
char *data = "lee/hom/jian/ll";
|
||||
char *data1 = "+/#";
|
||||
char *data2 = "+/+/+/+";
|
||||
struct topic_and_node *res = NULL;
|
||||
char **topic_queue = topic_parse(data);
|
||||
res = (struct topic_and_node*)zmalloc(sizeof(struct topic_and_node));
|
||||
search_node(db, topic_queue, res);
|
||||
|
||||
struct client ID2 = {"150410", NULL, NULL};
|
||||
add_node(res, &ID2);
|
||||
print_db_tree(db);
|
||||
|
||||
|
||||
topic_queue = topic_parse(data1);
|
||||
search_node(db, topic_queue, res);
|
||||
add_node(res, &ID2);
|
||||
print_db_tree(db);
|
||||
|
||||
topic_queue = topic_parse(data2);
|
||||
search_node(db, topic_queue, res);
|
||||
add_node(res, &ID2);
|
||||
print_db_tree(db);
|
||||
|
||||
struct clients *res_clients = NULL;
|
||||
struct client **client_queue = NULL;
|
||||
int cols = 0;
|
||||
topic_queue = topic_parse(data);
|
||||
res_clients = search_client(db->root, topic_queue);
|
||||
client_queue = iterate_client(res_clients, &cols);
|
||||
|
||||
while ((*client_queue) != NULL) {
|
||||
puts("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
|
||||
printf("%p %p \n", client_queue, *client_queue);
|
||||
printf("RES: client_queue is:%s\n", (*client_queue)->id);
|
||||
client_queue++;
|
||||
}
|
||||
|
||||
|
||||
// for (int i = 0; i < cols-1; i++) {
|
||||
// puts("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ssss&&&&&&");
|
||||
// printf("RES: client_queue is:%s\n", client_queue[i]->id);
|
||||
// }
|
||||
|
||||
|
||||
puts("----------------------------------------------------\nall:");
|
||||
while (res_clients) {
|
||||
struct client *sub_client = res_clients->sub_client;
|
||||
while (sub_client) {
|
||||
printf("RES: sub_client is:%s\n", sub_client->id);
|
||||
sub_client = sub_client->next;
|
||||
}
|
||||
res_clients = res_clients->down;
|
||||
}
|
||||
|
||||
// search_node(db, topic_queue, res);
|
||||
// del_client(res, ID2.id);
|
||||
// print_db_tree(db);
|
||||
|
||||
// del_node(res->node);
|
||||
// print_db_tree(db);
|
||||
|
||||
// topic_queue = topic_parse(data1);
|
||||
// search_node(db, topic_queue, res);
|
||||
// del_client(res, ID2.id);
|
||||
// print_db_tree(db);
|
||||
// del_node(res->node);
|
||||
// print_db_tree(db);
|
||||
|
||||
// topic_queue = topic_parse(data2);
|
||||
// search_node(db, topic_queue, res);
|
||||
// del_client(res, ID2.id);
|
||||
// print_db_tree(db);
|
||||
// del_node(res->node);
|
||||
// print_db_tree(db);
|
||||
}
|
||||
|
||||
static void Test_hash_alias(void)
|
||||
{
|
||||
puts(">>>>>>>>>>TEST_HASH_TABLE<<<<<<<<");
|
||||
int i = 1;
|
||||
int j = 2;
|
||||
int k = 3;
|
||||
char *topic1 = "topic1";
|
||||
char *topic2 = "topic2";
|
||||
char *topic3 = "topic3";
|
||||
printf("INPUT: %d --> %s\n", i, topic1);
|
||||
printf("INPUT: %d --> %s\n", j, topic2);
|
||||
printf("INPUT: %d --> %s\n", k, topic3);
|
||||
|
||||
|
||||
hash_add_alias(i, topic1);
|
||||
hash_add_alias(i, topic2);
|
||||
hash_add_alias(i, topic3);
|
||||
hash_add_alias(j, topic2);
|
||||
hash_add_alias(k, topic3);
|
||||
char* t1 = hash_check_alias(i);
|
||||
char* t2 = hash_check_alias(j);
|
||||
char* t3 = hash_check_alias(k);
|
||||
|
||||
printf("RES: %s\n", t1);
|
||||
printf("RES: %s\n", t2);
|
||||
printf("RES: %s\n", t3);
|
||||
hash_del_alias(i);
|
||||
hash_del_alias(j);
|
||||
hash_del_alias(k);
|
||||
t1 = hash_check_alias(i);
|
||||
t2 = hash_check_alias(j);
|
||||
t3 = hash_check_alias(k);
|
||||
if (t1) {
|
||||
printf("RES: %s\n", t1);
|
||||
}
|
||||
|
||||
if (t2) {
|
||||
printf("RES: %s\n", t2);
|
||||
}
|
||||
|
||||
if (t3) {
|
||||
printf("RES: %s\n", t3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void Test_topic_hash(void)
|
||||
{
|
||||
char *id = "150410";
|
||||
char *val = "lee/hom/jian";
|
||||
char *val1 = "#";
|
||||
char *val2 = "lee/#";
|
||||
char *val3 = "a/b/c";
|
||||
|
||||
if (check_id(id)) {
|
||||
puts("find");
|
||||
} else {
|
||||
puts("not find");
|
||||
}
|
||||
add_topic(id, val);
|
||||
add_topic(id, val1);
|
||||
add_topic(id, val2);
|
||||
add_topic(id, val3);
|
||||
|
||||
if (check_id(id)) {
|
||||
puts("find");
|
||||
} else {
|
||||
puts("not find");
|
||||
}
|
||||
|
||||
struct topic_queue *res = get_topic(id);
|
||||
while (res) {
|
||||
printf("res: %s\n", res->topic);
|
||||
res = res->next;
|
||||
}
|
||||
|
||||
// del_topic_one(id, val1);
|
||||
res = get_topic(id);
|
||||
while (res) {
|
||||
printf("res: %s\n", res->topic);
|
||||
res = res->next;
|
||||
}
|
||||
// del_topic_all(id);
|
||||
|
||||
if (check_id(id)) {
|
||||
puts("find");
|
||||
} else {
|
||||
puts("not find");
|
||||
}
|
||||
}
|
||||
|
||||
static void Test_pipe_hash(void)
|
||||
{
|
||||
uint32_t pipeid[] = {1, 2, 3, 4};
|
||||
char* clientid[] ={"150429", "150410", "150428", "150418"};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
add_pipe_id(pipeid[i], clientid[i]);
|
||||
printf("get_client_id %s\n", get_client_id(pipeid[i]));
|
||||
// del_pipe_id(pipeid[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void test(test_state what)
|
||||
{
|
||||
switch(what) {
|
||||
case test_topic_parse:
|
||||
Test_topic_parse();
|
||||
break;
|
||||
case test_search_node:
|
||||
Test_search_node();
|
||||
break;
|
||||
case test_add_node:
|
||||
Test_add_node();
|
||||
break;
|
||||
case test_del_node:
|
||||
Test_del_node();
|
||||
break;
|
||||
case test_hash_alias:
|
||||
Test_hash_alias();
|
||||
break;
|
||||
case test_topic_hash:
|
||||
Test_topic_hash();
|
||||
break;
|
||||
case test_pipe_hash:
|
||||
Test_pipe_hash();
|
||||
break;
|
||||
default:
|
||||
log("No this state");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void help()
|
||||
{
|
||||
printf("please input the right num to conduct diff test\n");
|
||||
printf(" test_topic_parse, 0\n");
|
||||
printf(" test_search_node, 1\n");
|
||||
printf(" test_add_node, 2\n");
|
||||
printf(" test_del_node, 3\n");
|
||||
printf(" test_hash_alias, 4\n");
|
||||
printf(" test_topic_hash, 5\n");
|
||||
printf(" test_pipe_hash, 6\n");
|
||||
printf(" quit q\n");
|
||||
printf(" help h\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
puts("\n----------------TEST START------------------");
|
||||
char str[5];
|
||||
create_db_tree(&db);
|
||||
help();
|
||||
|
||||
while (1) {
|
||||
printf("input:");
|
||||
scanf("%s", str);
|
||||
if (!strcmp(str, "q")) {
|
||||
break;
|
||||
} else if (!strcmp(str, "h")) {
|
||||
help();
|
||||
continue;
|
||||
}
|
||||
|
||||
int i = atoi(str);
|
||||
test((test_state)i);
|
||||
}
|
||||
|
||||
int i = 2;
|
||||
puts("11111");
|
||||
print_db_tree(db);
|
||||
del_all(i, db);
|
||||
puts("22222");
|
||||
print_db_tree(db);
|
||||
puts("---------------TEST FINISHED----------------\n");
|
||||
return 0;
|
||||
}
|
||||
|
142
nanolib/zmalloc.c
Normal file
142
nanolib/zmalloc.c
Normal file
@ -0,0 +1,142 @@
|
||||
/* zmalloc - total amount of allocated memory aware version of malloc()
|
||||
*
|
||||
* Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
** Remove pthread by Ery Lee
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(__sun)
|
||||
#define PREFIX_SIZE sizeof(long long)
|
||||
#else
|
||||
#define PREFIX_SIZE sizeof(size_t)
|
||||
#endif
|
||||
|
||||
#define increment_used_memory(__n) do { \
|
||||
size_t _n = (__n); \
|
||||
if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
|
||||
used_memory += _n; \
|
||||
} while(0)
|
||||
|
||||
#define decrement_used_memory(__n) do { \
|
||||
size_t _n = (__n); \
|
||||
if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
|
||||
used_memory -= _n; \
|
||||
} while(0)
|
||||
|
||||
static size_t used_memory = 0;
|
||||
|
||||
static void zmalloc_oom(size_t size) {
|
||||
fprintf(stderr, "zmalloc: Out of memory trying to allocate %zu bytes\n",
|
||||
size);
|
||||
fflush(stderr);
|
||||
abort();
|
||||
}
|
||||
|
||||
void *zmalloc(size_t size) {
|
||||
void *ptr = malloc(size+PREFIX_SIZE);
|
||||
|
||||
if (!ptr) zmalloc_oom(size);
|
||||
#ifdef HAVE_MALLOC_SIZE
|
||||
increment_used_memory(redis_malloc_size(ptr));
|
||||
return ptr;
|
||||
#else
|
||||
*((size_t*)ptr) = size;
|
||||
increment_used_memory(size+PREFIX_SIZE);
|
||||
return (char*)ptr+PREFIX_SIZE;
|
||||
#endif
|
||||
}
|
||||
|
||||
void *zrealloc(void *ptr, size_t size) {
|
||||
#ifndef HAVE_MALLOC_SIZE
|
||||
void *realptr;
|
||||
#endif
|
||||
size_t oldsize;
|
||||
void *newptr;
|
||||
|
||||
if (ptr == NULL) return zmalloc(size);
|
||||
#ifdef HAVE_MALLOC_SIZE
|
||||
oldsize = redis_malloc_size(ptr);
|
||||
newptr = realloc(ptr,size);
|
||||
if (!newptr) zmalloc_oom(size);
|
||||
|
||||
decrement_used_memory(oldsize);
|
||||
increment_used_memory(redis_malloc_size(newptr));
|
||||
return newptr;
|
||||
#else
|
||||
realptr = (char*)ptr-PREFIX_SIZE;
|
||||
oldsize = *((size_t*)realptr);
|
||||
newptr = realloc(realptr,size+PREFIX_SIZE);
|
||||
if (!newptr) zmalloc_oom(size);
|
||||
|
||||
*((size_t*)newptr) = size;
|
||||
decrement_used_memory(oldsize);
|
||||
increment_used_memory(size);
|
||||
return (char*)newptr+PREFIX_SIZE;
|
||||
#endif
|
||||
}
|
||||
|
||||
void zfree(void *ptr) {
|
||||
#ifndef HAVE_MALLOC_SIZE
|
||||
void *realptr;
|
||||
size_t oldsize;
|
||||
#endif
|
||||
|
||||
if (ptr == NULL) return;
|
||||
#ifdef HAVE_MALLOC_SIZE
|
||||
decrement_used_memory(redis_malloc_size(ptr));
|
||||
free(ptr);
|
||||
#else
|
||||
realptr = (char*)ptr-PREFIX_SIZE;
|
||||
oldsize = *((size_t*)realptr);
|
||||
decrement_used_memory(oldsize+PREFIX_SIZE);
|
||||
free(realptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
char *zstrdup(const char *s) {
|
||||
size_t l = strlen(s)+1;
|
||||
char *p = zmalloc(l);
|
||||
|
||||
memcpy(p,s,l);
|
||||
return p;
|
||||
}
|
||||
|
||||
size_t zmalloc_used_memory(void) {
|
||||
size_t um;
|
||||
|
||||
um = used_memory;
|
||||
|
||||
return um;
|
||||
}
|
||||
|
38
nanomq/CMakeLists.txt
Normal file
38
nanomq/CMakeLists.txt
Normal file
@ -0,0 +1,38 @@
|
||||
#
|
||||
# This software is supplied under the terms of the MIT License, a
|
||||
# copy of which should be located in the distribution where this
|
||||
# file was obtained (LICENSE.txt). A copy of the license may also be
|
||||
# found online at https://opensource.org/licenses/MIT.
|
||||
|
||||
cmake_minimum_required (VERSION 2.8.8)
|
||||
|
||||
project(nanomq)
|
||||
SET(CMAKE_C_FLAGS "-std=c99")
|
||||
SET(CMAKE_CXX_FLAGS "-std=c++11 -O3")
|
||||
|
||||
aux_source_directory(. DIRSRCS)
|
||||
|
||||
include_directories(./ ./apps ./include)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/nng/include/nng)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/nanolib/include)
|
||||
|
||||
add_subdirectory(apps)
|
||||
|
||||
set(PARALLEL 128 CACHE STRING "Parallelism (min 4, max 1000)")
|
||||
|
||||
# Call this from your own project's makefile.
|
||||
find_package(nng CONFIG REQUIRED)
|
||||
find_package(nanolib CONFIG REQUIRED)
|
||||
#if (NANOLIB_FOUND)
|
||||
# INCLUDE_DIRECTORIES(${NANOLIB_INCLUDE_DIR})
|
||||
# TARGET_LINK_LIBRARIES(nanomq ${NANOLIB_LIBRARY})
|
||||
#else (NANOLIB_FOUND)
|
||||
# MESSAGE(FATAL_ERROR "nanolib library not found")
|
||||
|
||||
|
||||
add_executable(nanomq nanomq.c cmd.c file.c process.c apps.c pub_handler.c subscribe_handle.c unsubscribe_handle.c)
|
||||
|
||||
#target_link_libraries(nanomq apps nano_shared)
|
||||
target_link_libraries(nanomq apps nanolib)
|
||||
target_link_libraries(nanomq nng)
|
||||
target_compile_definitions(nanomq PRIVATE -DPARALLEL=${PARALLEL})
|
44
nanomq/Makefile
Normal file
44
nanomq/Makefile
Normal file
@ -0,0 +1,44 @@
|
||||
#
|
||||
# Copyright (C) 2019 EMQX, Inc. Jaylin Yu
|
||||
#
|
||||
|
||||
CC = gcc
|
||||
CFLAGS += -Wall -fno-strict-aliasing -W -std=gnu99
|
||||
CFLAGS += -I. -Ishared/ -Iconfig/ -Icheckin/ -Iapps/ `pkg-config --cflags `
|
||||
OFLAGS += -Os
|
||||
CPPFLAGS="-D PARALLEL=32 -I /usr/local/include"
|
||||
LDFLAGS2="-L /usr/local/lib -lnng"
|
||||
CC2="cc"
|
||||
LDFLAGS += $(OFLAGS) -lrt `pkg-config`
|
||||
|
||||
EXTRA_CFLAGS += -DDEBUG_CONSOLE
|
||||
# EXTRA_CFLAGS += -DDEBUG_FILE
|
||||
EXTRA_CFLAGS += -DDEBUG_SYSLOG
|
||||
# EXTRA_CFLAGS += -DDEBUG_TRACE
|
||||
|
||||
SRC_C = nanomq.c apps.c cmd.c process.c file.c const_string.c $(wildcard apps/*.c) $(wildcard config/*.c) $(wildcard shared/*.c) $(wildcard checkin/*.c)
|
||||
SRC_H = ./include/nanomq.h ./include/apps.h $(wildcard apps/*.h) $(wildcard config/*.h) $(wildcard shared/*.h) $(wildcard checkin/*.h) $(wildcard include/*.h)
|
||||
SRC_O = $(SRC_C:.c=.o)
|
||||
|
||||
ifneq ($(CONFIG_REGDBQUERY_STATIC_ONLY), y)
|
||||
$(warning Makefile is valid!)
|
||||
endif
|
||||
|
||||
ifeq ($(EMQ_DEBUG), y)
|
||||
EXTRA_CFLAGS += -DDEBUG_CONSOLE
|
||||
EXTRA_CFLAGS += -DDEBUG_SYSLOG
|
||||
endif
|
||||
|
||||
CFLAGS +=
|
||||
LDFLAGS += -Wl,-Bstatic -Wl,-Bdynamic
|
||||
|
||||
nanomq: $(SRC_O) $(SRC_H) Makefile
|
||||
$(CC) -o $@ $(SRC_O) $(LDFLAGS)
|
||||
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_CFLAGS) -MD -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -f nanomq *.o *~ apps/*.o apps/*~ config/*.o config/*~ shared/*.o shared/*~
|
||||
rm -f `find . -name '*.d' -print`
|
27
nanomq/README.adoc
Normal file
27
nanomq/README.adoc
Normal file
@ -0,0 +1,27 @@
|
||||
NanoMQ base on NNG's AIO threading model. Rewriting the TCP/SP part with self-added protocol emq_tcp.
|
||||
|
||||
Basically you need to compile and install the nng first:
|
||||
|
||||
$PROJECT_PATH/nanomq/build$ cmake -G Ninja ..
|
||||
or you can limit threads by
|
||||
cmake -G Ninja -DNNG_RESOLV_CONCURRENCY=1 -DNNG_NUM_TASKQ_THREADS=2 -DNNG_MAX_TASKQ_THREADS=2 ..
|
||||
|
||||
$PROJECT_PATH/nanomq/build$ ninja
|
||||
$PROJECT_PATH/nanomq/build$ ninja install
|
||||
|
||||
then compile nanomq independently:
|
||||
$PROJECT_PATH/nanomq/emq/nanomq/build$ cmake -G Ninja ..
|
||||
$PROJECT_PATH/nanomq/emq/nanomq/build$ ninja
|
||||
|
||||
In the future, We will trying to figure out a way to support MQTT without damaging NNG's SP support.
|
||||
Also rewrite CMake and MakeFile so that user can compile nng-emq version with nanomq together.
|
||||
|
||||
===============================================
|
||||
|
||||
usage:
|
||||
|
||||
#ongoing MQTT Broker/ only a plain TCP server for now
|
||||
sudo ./nanomq broker start 'tcp://localhost:1883'
|
||||
|
||||
#test POSIX message Queue
|
||||
sudo ./nanomq broker mq start/stop
|
22
nanomq/apps.c
Normal file
22
nanomq/apps.c
Normal file
@ -0,0 +1,22 @@
|
||||
|
||||
#include "include/apps.h"
|
||||
#include "broker.h"
|
||||
#include "mq.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
NANOMQ_APP(mq, mqcreate_debug, mqsend_debug, mqreceive_debug);
|
||||
NANOMQ_APP(broker, broker_dflt, broker_start, NULL);
|
||||
|
||||
#if defined(NANO_DEBUG)
|
||||
|
||||
#endif
|
||||
|
||||
const struct nanomq_app *edge_apps[] = {
|
||||
&nanomq_app_mq,
|
||||
&nanomq_app_broker,
|
||||
#if defined(NANO_DEBUG)
|
||||
//&
|
||||
#endif
|
||||
NULL,
|
||||
};
|
1
nanomq/apps/.kdev_include_paths
Normal file
1
nanomq/apps/.kdev_include_paths
Normal file
@ -0,0 +1 @@
|
||||
RESOLVE: SOURCE=/home/jaylin/CodeWarehouse/OpenWRT/sdk/EV_Router_SDK/package/libev BUILD=
|
19
nanomq/apps/CMakeLists.txt
Normal file
19
nanomq/apps/CMakeLists.txt
Normal file
@ -0,0 +1,19 @@
|
||||
aux_source_directory(. DIR_LIB_SRCS)
|
||||
include_directories(../include)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/nng/include/nng)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/nanolib/include)
|
||||
|
||||
find_library(LIBRT rt)
|
||||
|
||||
find_package(nng CONFIG REQUIRED)
|
||||
find_package(nanolib REQUIRED)
|
||||
|
||||
set(PARALLEL 128 CACHE STRING "Parallelism (min 4, max 1000)")
|
||||
|
||||
add_library (apps ${DIR_LIB_SRCS})
|
||||
target_link_libraries(apps ${LIBRT})
|
||||
|
||||
target_link_libraries(apps nng)
|
||||
#target_link_libraries(apps nano_shared)
|
||||
target_link_libraries(apps nanolib)
|
||||
target_compile_definitions(apps PRIVATE -DPARALLEL=${PARALLEL})
|
415
nanomq/apps/broker.c
Normal file
415
nanomq/apps/broker.c
Normal file
@ -0,0 +1,415 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <protocol/mqtt/mqtt_parser.h>
|
||||
#include <nng.h>
|
||||
#include <mqtt_db.h>
|
||||
#include <hash.h>
|
||||
|
||||
#include "include/nanomq.h"
|
||||
#include "include/pub_handler.h"
|
||||
#include "include/subscribe_handle.h"
|
||||
#include "include/unsubscribe_handle.h"
|
||||
|
||||
// Parallel is the maximum number of outstanding requests we can handle.
|
||||
// This is *NOT* the number of threads in use, but instead represents
|
||||
// outstanding work items. Select a small number to reduce memory size.
|
||||
// (Each one of these can be thought of as a request-reply loop.) Note
|
||||
// that you will probably run into limitations on the number of open file
|
||||
// descriptors if you set this too high. (If not for that limit, this could
|
||||
// be set in the thousands, each context consumes a couple of KB.)
|
||||
// #ifndef PARALLEL
|
||||
// #define PARALLEL 128
|
||||
// #endif
|
||||
#define PARALLEL 128
|
||||
|
||||
// The server keeps a list of work items, sorted by expiration time,
|
||||
// so that we can use this to set the timeout to the correct value for
|
||||
// use in poll.
|
||||
|
||||
void
|
||||
fatal(const char *func, int rv)
|
||||
{
|
||||
fprintf(stderr, "%s: %s\n", func, nng_strerror(rv));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void transmit_msgs_cb(nng_msg *send_msg, emq_work *work, uint32_t *pipes)
|
||||
{
|
||||
work->state = SEND;
|
||||
work->msg = send_msg;//FIXME should be encode message for each sub cilent due to different minimum QoS
|
||||
nng_aio_set_msg(work->aio, send_msg);
|
||||
work->msg = NULL;
|
||||
|
||||
nng_aio_set_pipeline(work->aio, pipes);
|
||||
nng_ctx_send(work->ctx, work->aio);
|
||||
}
|
||||
|
||||
|
||||
/*objective: 1 input/output low latency
|
||||
2 KV
|
||||
3 tree
|
||||
*/
|
||||
void
|
||||
server_cb(void *arg)
|
||||
{
|
||||
emq_work *work = arg;
|
||||
nng_ctx ctx2;
|
||||
nng_msg *msg;
|
||||
nng_msg *smsg;
|
||||
nng_pipe pipe;
|
||||
int rv;
|
||||
uint32_t when;
|
||||
|
||||
uint32_t *pipes = NULL;
|
||||
// struct pipe_nng_msg *pipe_msgs = NULL;
|
||||
|
||||
reason_code reason;
|
||||
uint8_t buf[2];
|
||||
|
||||
switch (work->state) {
|
||||
case INIT:
|
||||
debug_msg("INIT ^^^^^^^^^^^^^^^^^^^^^ \n");
|
||||
work->state = RECV;
|
||||
nng_ctx_recv(work->ctx, work->aio);
|
||||
debug_msg("INIT!!\n");
|
||||
break;
|
||||
case RECV:
|
||||
debug_msg("RECV ^^^^^^^^^^^^^^^^^^^^^ %d ^^^^\n", work->ctx.id);
|
||||
if ((rv = nng_aio_result(work->aio)) != 0) {
|
||||
debug_msg("ERROR: RECV nng aio result error: %d", rv);
|
||||
nng_aio_wait(work->aio);
|
||||
//break;
|
||||
fatal("RECV nng_ctx_recv", rv);
|
||||
}
|
||||
msg = nng_aio_get_msg(work->aio);
|
||||
if (msg == NULL) { //BUG
|
||||
debug_msg("ERROR: RECV NULL msg");
|
||||
//fatal("RECV NULL MSG", rv);
|
||||
}
|
||||
pipe = nng_msg_get_pipe(msg);
|
||||
debug_msg("RECVIED %d %x\n", work->ctx.id, nng_msg_cmd_type(msg));
|
||||
|
||||
if (nng_msg_cmd_type(msg) == CMD_DISCONNECT) {
|
||||
/**/
|
||||
work->cparam = (conn_param *) nng_msg_get_conn_param(msg);
|
||||
char *clientid = (char *) conn_param_get_clentid(work->cparam);
|
||||
struct topic_and_node *tan = nng_alloc(sizeof(struct topic_and_node));
|
||||
struct client *cli = NULL;
|
||||
struct topic_queue *tq = NULL;
|
||||
|
||||
debug_msg("##########DISCONNECT (clientID:[%s])##########", clientid);
|
||||
if (check_id(clientid)) {
|
||||
tq = get_topic(clientid);
|
||||
while (tq) {
|
||||
if (tq->topic) {
|
||||
search_node(work->db, topic_parse(tq->topic), tan);
|
||||
if ((cli = del_client(tan, clientid)) == NULL) {
|
||||
break;
|
||||
}
|
||||
del_pipe_id(pipe.id);
|
||||
}
|
||||
if (cli) {
|
||||
del_node(tan->node);
|
||||
debug_msg("Destroy CTX [%p] clientID: [%s]", cli->ctxt, cli->id);
|
||||
destroy_sub_ctx(cli->ctxt, tq->topic); // only free work->sub_pkt
|
||||
nng_free(cli, sizeof(struct client));
|
||||
}
|
||||
if (check_id(clientid)) {
|
||||
tq = tq->next;
|
||||
}
|
||||
}
|
||||
del_topic_all(clientid);
|
||||
del_pipe_id(pipe.id);
|
||||
nng_free(tan, sizeof(struct topic_and_node));
|
||||
debug_msg("INHASH: clientid [%s] exist?: [%d]; pipeid [%d] exist?: [%d]",
|
||||
clientid, (int) check_id(clientid), pipe.id, (int) check_pipe_id(pipe.id));
|
||||
}
|
||||
work->state = RECV;
|
||||
nng_msg_free(msg);
|
||||
work->msg = NULL;
|
||||
nng_aio_abort(work->aio, 31);
|
||||
nng_ctx_recv(work->ctx, work->aio);
|
||||
break;
|
||||
}
|
||||
|
||||
work->msg = msg;
|
||||
work->state = WAIT;
|
||||
debug_msg("RECV ********************* msg: %s %x******************************************\n",
|
||||
(char *) nng_msg_body(work->msg), nng_msg_cmd_type(work->msg));
|
||||
nng_sleep_aio(100, work->aio);
|
||||
break;
|
||||
case WAIT:
|
||||
debug_msg("WAIT ^^^^^^^^^^^^^^^^^^^^^ %d ^^^^", work->ctx.id);
|
||||
// We could add more data to the message here.
|
||||
work->cparam = (conn_param *) nng_msg_get_conn_param(work->msg);
|
||||
//debug_msg("WAIT %x %s %d pipe: %d\n", nng_msg_cmd_type(work->msg),
|
||||
//conn_param_get_clentid(work->cparam), work->ctx.id, work->pid.id);
|
||||
/*
|
||||
if ((rv = nng_msg_append_u32(msg, msec)) != 0) {
|
||||
fatal("nng_msg_append_u32", rv);
|
||||
}
|
||||
*/
|
||||
//reply to client if needed. nng_send_aio vs nng_sendmsg? async or sync? BETTER sync due to realtime requirement
|
||||
//TODO
|
||||
if ((rv = nng_msg_alloc(&smsg, 0)) != 0) {
|
||||
debug_msg("error nng_msg_alloc^^^^^^^^^^^^^^^^^^^^^");
|
||||
}
|
||||
if (nng_msg_cmd_type(work->msg) == CMD_PINGREQ) {
|
||||
buf[0] = CMD_PINGRESP;
|
||||
buf[1] = 0x00;
|
||||
debug_msg("reply PINGRESP\n");
|
||||
|
||||
if ((rv = nng_msg_header_append(smsg, buf, 2)) != 0) {
|
||||
debug_msg("error nng_msg_append^^^^^^^^^^^^^^^^^^^^^");
|
||||
}
|
||||
nng_msg_free(work->msg);
|
||||
work->msg = smsg;
|
||||
// We could add more data to the message here.
|
||||
nng_aio_set_msg(work->aio, work->msg);
|
||||
|
||||
work->msg = NULL;
|
||||
work->state = SEND;
|
||||
nng_ctx_send(work->ctx, work->aio);
|
||||
break;
|
||||
|
||||
} else if (nng_msg_cmd_type(work->msg) == CMD_SUBSCRIBE) {
|
||||
pipe = nng_msg_get_pipe(work->msg);
|
||||
work->pid = pipe;
|
||||
debug_msg("get pipe!! ^^^^^^^^^^^^^^^^^^^^^ %d %d\n", pipe.id, work->pid.id);
|
||||
work->sub_pkt = nng_alloc(sizeof(struct packet_subscribe));
|
||||
if ((reason = decode_sub_message(work->msg, work->sub_pkt)) != SUCCESS ||
|
||||
(reason = sub_ctx_handle(work)) != SUCCESS ||
|
||||
(reason = encode_suback_message(smsg, work->sub_pkt)) != SUCCESS) {
|
||||
debug_msg("ERROR IN SUB_HANDLE: %d", reason);
|
||||
// TODO free sub_pkt
|
||||
} else {
|
||||
// success but check info
|
||||
debug_msg("In sub_pkt: pktid:%d, topicLen: %d, topic: %s", work->sub_pkt->packet_id,
|
||||
work->sub_pkt->node->it->topic_filter.len,
|
||||
work->sub_pkt->node->it->topic_filter.str_body);
|
||||
debug_msg("SUBACK: Header Len: %ld, Body Len: %ld. In Body. TYPE:%x LEN:%x PKTID: %x %x.",
|
||||
nng_msg_header_len(smsg), nng_msg_len(smsg), *((uint8_t *) nng_msg_header(smsg)),
|
||||
*((uint8_t *) nng_msg_header(smsg) + 1), *((uint8_t *) nng_msg_body(smsg)),
|
||||
*((uint8_t *) nng_msg_body(smsg) + 1));
|
||||
}
|
||||
nng_msg_free(work->msg);
|
||||
|
||||
work->msg = smsg;
|
||||
// We could add more data to the message here.
|
||||
nng_aio_set_msg(work->aio, work->msg);
|
||||
work->msg = NULL;
|
||||
work->state = SEND;
|
||||
nng_ctx_send(work->ctx, work->aio);
|
||||
break;
|
||||
//nng_send_aio
|
||||
} else if (nng_msg_cmd_type(work->msg) == CMD_UNSUBSCRIBE) {
|
||||
work->unsub_pkt = nng_alloc(sizeof(struct packet_unsubscribe));
|
||||
if ((reason = decode_unsub_message(work->msg, work->unsub_pkt)) != SUCCESS ||
|
||||
(reason = unsub_ctx_handle(work)) != SUCCESS ||
|
||||
(reason = encode_unsuback_message(smsg, work->unsub_pkt)) != SUCCESS) {
|
||||
debug_msg("ERROR IN UNSUB_HANDLE: %d", reason);
|
||||
// TODO free unsub_pkt
|
||||
} else {
|
||||
// check info
|
||||
debug_msg("In unsub_pkt: pktid:%d, topicLen: %d", work->unsub_pkt->packet_id,
|
||||
work->unsub_pkt->node->it->topic_filter.len);
|
||||
debug_msg("Header Len: %ld, Body Len: %ld.", nng_msg_header_len(smsg), nng_msg_len(smsg));
|
||||
debug_msg("In Body. TYPE:%x LEN:%x PKTID: %x %x.", *((uint8_t *) nng_msg_header(smsg)),
|
||||
*((uint8_t *) nng_msg_header(smsg) + 1), *((uint8_t *) nng_msg_body(smsg)),
|
||||
*((uint8_t *) nng_msg_body(smsg) + 1));
|
||||
}
|
||||
nng_msg_free(work->msg);
|
||||
|
||||
work->msg = smsg;
|
||||
// We could add more data to the message here.
|
||||
nng_aio_set_msg(work->aio, work->msg);
|
||||
work->msg = NULL;
|
||||
work->state = SEND;
|
||||
nng_ctx_send(work->ctx, work->aio);
|
||||
break;
|
||||
} else if (nng_msg_cmd_type(work->msg) == CMD_PUBLISH ||
|
||||
nng_msg_cmd_type(work->msg) == CMD_PUBACK ||
|
||||
nng_msg_cmd_type(work->msg) == CMD_PUBREC ||
|
||||
nng_msg_cmd_type(work->msg) == CMD_PUBREL ||
|
||||
nng_msg_cmd_type(work->msg) == CMD_PUBCOMP) {
|
||||
|
||||
//nng_mtx_lock(work->mutex);
|
||||
if ((rv = nng_aio_result(work->aio)) != 0) {
|
||||
debug_msg("WAIT nng aio result error: %d", rv);
|
||||
fatal("WAIT nng_ctx_recv/send", rv);
|
||||
//nng_aio_wait(work->aio);
|
||||
//break;
|
||||
}
|
||||
|
||||
#if DISTRIBUTE_DIFF_MSG
|
||||
handle_pub(work, smsg, (void **) &work->pipe_msgs, NULL);
|
||||
nng_msg_free(work->msg);
|
||||
|
||||
if (work->pipe_msgs != NULL) {
|
||||
debug_msg("set pipeline[%d]: [%d]", work->pipe_msgs[0].index, work->pipe_msgs[0].pipe);
|
||||
work->msg = work->pipe_msgs[0].msg;
|
||||
nng_aio_set_msg(work->aio, work->msg);
|
||||
work->msg = NULL;
|
||||
work->state = SEND;
|
||||
|
||||
nng_aio_set_pipeline(work->aio, work->pipe_msgs[0].pipe);
|
||||
work->index = 1;
|
||||
nng_ctx_send(work->ctx, work->aio);
|
||||
}
|
||||
#else
|
||||
handle_pub(work, smsg, pipes, transmit_msgs_cb);
|
||||
|
||||
#endif
|
||||
if (work->state != SEND) {
|
||||
nng_msg_free(smsg);
|
||||
if (work->msg != NULL)
|
||||
nng_msg_free(work->msg);
|
||||
work->msg = NULL;
|
||||
work->state = RECV;
|
||||
nng_ctx_recv(work->ctx, work->aio);
|
||||
}
|
||||
//nng_mtx_unlock(work->mutex);
|
||||
|
||||
} else {
|
||||
debug_msg("broker has nothing to do");
|
||||
nng_msg_free(smsg);
|
||||
if (work->msg != NULL)
|
||||
nng_msg_free(work->msg);
|
||||
work->msg = NULL;
|
||||
work->state = RECV;
|
||||
nng_ctx_recv(work->ctx, work->aio);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SEND:
|
||||
debug_msg("SEND ^^^^^^^^^^^^^^^^^^^^^ %d ^^^^\n", work->ctx.id);
|
||||
if ((rv = nng_aio_result(work->aio)) != 0) {
|
||||
debug_msg("SEND nng aio result error: %d", rv);
|
||||
fatal("SEND nng_ctx_send", rv);
|
||||
} else if ((smsg = nng_aio_get_msg(work->aio)) != NULL) {
|
||||
nng_msg_free(smsg);
|
||||
}
|
||||
|
||||
#if DISTRIBUTE_DIFF_MSG
|
||||
if (work->pipe_msgs != NULL && work->pipe_msgs[work->index].pipe != 0) {
|
||||
debug_msg("set pipeline[%d] %d: [%d]", work->pipe_msgs[work->index].index, work->index, work->pipe_msgs[work->index].pipe);
|
||||
work->msg = work->pipe_msgs[work->index].msg;
|
||||
nng_aio_set_msg(work->aio, work->msg);
|
||||
work->msg = NULL;
|
||||
work->state = SEND;
|
||||
nng_aio_set_pipeline(work->aio, work->pipe_msgs[work->index].pipe);
|
||||
work->index ++;
|
||||
if (work->pipe_msgs[work->index].pipe == 0) {
|
||||
free(work->pipe_msgs);
|
||||
work->pipe_msgs = NULL;
|
||||
}
|
||||
nng_ctx_send(work->ctx, work->aio);
|
||||
break;
|
||||
} else {
|
||||
work->msg = NULL;
|
||||
work->state = RECV;
|
||||
nng_ctx_recv(work->ctx, work->aio);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
if (pipes != NULL) {
|
||||
free(pipes);
|
||||
pipes = NULL;
|
||||
}
|
||||
#endif
|
||||
work->msg = NULL;
|
||||
work->state = RECV;
|
||||
nng_ctx_recv(work->ctx, work->aio);
|
||||
break;
|
||||
default:
|
||||
fatal("bad state!", NNG_ESTATE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct work *
|
||||
alloc_work(nng_socket sock)
|
||||
{
|
||||
struct work *w;
|
||||
int rv;
|
||||
|
||||
if ((w = nng_alloc(sizeof(*w))) == NULL) {
|
||||
fatal("nng_alloc", NNG_ENOMEM);
|
||||
}
|
||||
if ((rv = nng_aio_alloc(&w->aio, server_cb, w)) != 0) {
|
||||
fatal("nng_aio_alloc", rv);
|
||||
}
|
||||
//not pipe id; max id = uint32_t
|
||||
if ((rv = nng_ctx_open(&w->ctx, sock)) != 0) {
|
||||
fatal("nng_ctx_open", rv);
|
||||
}
|
||||
if ((rv = nng_mtx_alloc(&w->mutex)) != 0) {
|
||||
fatal("nng_mtx_alloc", rv);
|
||||
}
|
||||
w->pipe_msgs = NULL;
|
||||
w->index = 0;
|
||||
|
||||
w->state = INIT;
|
||||
return (w);
|
||||
}
|
||||
|
||||
// The server runs forever.
|
||||
int
|
||||
server(const char *url)
|
||||
{
|
||||
nng_socket sock;
|
||||
nng_pipe pipe_id;
|
||||
struct work *works[PARALLEL];
|
||||
int rv;
|
||||
int i;
|
||||
// init tree
|
||||
struct db_tree *db = NULL;
|
||||
create_db_tree(&db);
|
||||
|
||||
/* Create the socket. */
|
||||
rv = nng_nano_tcp0_open(&sock);
|
||||
if (rv != 0) {
|
||||
fatal("nng_nano_tcp0_open", rv);
|
||||
}
|
||||
|
||||
debug_msg("PARALLEL: %d\n", PARALLEL);
|
||||
for (i = 0; i < PARALLEL; i++) {
|
||||
works[i] = alloc_work(sock);
|
||||
works[i]->db = db;
|
||||
nng_aio_set_dbtree(works[i]->aio, db);
|
||||
// works[i]->pid = pipe_id;
|
||||
}
|
||||
|
||||
if ((rv = nng_listen(sock, url, NULL, 0)) != 0) {
|
||||
fatal("nng_listen", rv);
|
||||
}
|
||||
|
||||
for (i = 0; i < PARALLEL; i++) {
|
||||
server_cb(works[i]); // this starts them going (INIT state)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
nng_msleep(3600000); // neither pause() nor sleep() portable
|
||||
}
|
||||
}
|
||||
|
||||
int broker_start(int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
if (argc != 1) {
|
||||
fprintf(stderr, "Usage: broker start <url>\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
rc = server(argv[0]);
|
||||
exit(rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int broker_dflt(int argc, char **argv)
|
||||
{
|
||||
debug_msg("i dont know what to do here yet");
|
||||
return 0;
|
||||
}
|
32
nanomq/apps/broker.h
Normal file
32
nanomq/apps/broker.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef NANOMQ_BROKER_H
|
||||
#define NANOMQ_BROKER_H
|
||||
#define MQTT_VER 5
|
||||
|
||||
#include <nng/nng.h>
|
||||
#include <nng/supplemental/util/platform.h>
|
||||
#include <nng/protocol/mqtt/mqtt.h>
|
||||
|
||||
struct work {
|
||||
int index;
|
||||
enum { INIT, RECV, WAIT, SEND } state;
|
||||
nng_aio *aio;
|
||||
nng_msg *msg;
|
||||
nng_ctx ctx;
|
||||
nng_pipe pid;
|
||||
nng_mtx *mutex;
|
||||
struct db_tree *db;
|
||||
conn_param *cparam;
|
||||
struct pub_packet_struct *pub_packet;
|
||||
struct packet_subscribe * sub_pkt;
|
||||
struct packet_unsubscribe * unsub_pkt;
|
||||
struct pipe_nng_msg *pipe_msgs;
|
||||
};
|
||||
|
||||
|
||||
typedef struct work emq_work;
|
||||
|
||||
int broker_start(int argc, char **argv);
|
||||
|
||||
int broker_dflt(int argc, char **argv);
|
||||
|
||||
#endif
|
126
nanomq/apps/mq.c
Normal file
126
nanomq/apps/mq.c
Normal file
@ -0,0 +1,126 @@
|
||||
#include "mq.h"
|
||||
#include "include/nanomq.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <mqueue.h>
|
||||
|
||||
|
||||
#define FILEMODE (S_IRUSR | S_IWUSR | S_IRGRP |S_IWGRP)
|
||||
struct mq_attr attr;
|
||||
|
||||
int mqcreate_debug(int argc, char **argv, char NANO_UNUSED(*extra_arg))
|
||||
{
|
||||
int c, flags;
|
||||
mqd_t mqd;
|
||||
|
||||
flags = O_RDWR | O_CREAT;
|
||||
while((c = getopt(argc, argv, "em:z:")) != -1) {//处理参数,带冒号的表示后面有参数的
|
||||
switch(c) {
|
||||
case 'e':
|
||||
flags |= O_EXCL;
|
||||
printf("the optind is :%d\n",optind);
|
||||
break;
|
||||
case 'm':
|
||||
attr.mq_maxmsg = atol(optarg);
|
||||
printf("the optind is :%d\n",optind);
|
||||
break;
|
||||
case 'z':
|
||||
attr.mq_msgsize = atol(optarg);
|
||||
printf("the optind is :%d\n",optind);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (optind != argc - 1) {
|
||||
debug_msg("usage: mqcreate [-e] [-m maxmsg -z msgsize] <name>");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ((attr.mq_maxmsg != 0 && attr.mq_msgsize == 0) || (attr.mq_maxmsg == 0 && attr.mq_msgsize !=0)){
|
||||
debug_msg("must specify both -m maxmsg and -z msgsize");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
mqd = mq_open(argv[optind], flags, FILEMODE, (attr.mq_maxmsg != 0) ? &attr : NULL);
|
||||
debug_msg("%d %d", mqd, errno);
|
||||
mq_close(mqd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mqreceive_debug(int argc, char **argv, char NANO_UNUSED(*extra_arg))
|
||||
{
|
||||
int flags;
|
||||
mqd_t mqd;
|
||||
ssize_t n;
|
||||
unsigned int prio;
|
||||
char *buff;
|
||||
struct mq_attr attr;
|
||||
struct timespec abs_timeout;
|
||||
flags = O_RDONLY;
|
||||
clock_gettime(CLOCK_REALTIME, &abs_timeout);
|
||||
abs_timeout.tv_sec+=4;
|
||||
|
||||
if (optind != argc-1) {
|
||||
debug_msg("usage: mqreceive <name>");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
mqd = mq_open(argv[optind], flags);
|
||||
mq_getattr(mqd, &attr);
|
||||
|
||||
buff = malloc(attr.mq_msgsize);
|
||||
|
||||
//n = mq_receive(mqd, buff, attr.mq_msgsize, &prio);
|
||||
debug_msg("%ld", abs_timeout.tv_sec);
|
||||
n = (mq_timedreceive(mqd, buff, attr.mq_msgsize, &prio, &abs_timeout));
|
||||
mq_close(mqd);
|
||||
debug_msg("read %ld bytes, priority = %u buffer = %s\n",(long) n, prio, buff);
|
||||
free(buff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mqsend_debug(int argc, char **argv, char NANO_UNUSED(*extra_arg))
|
||||
{
|
||||
mqd_t mqd;
|
||||
char *ptr;
|
||||
unsigned int prio;
|
||||
|
||||
if (argc != 4) {
|
||||
printf("usage: mqsend <name> <bytes> <priority>");
|
||||
exit(0);
|
||||
}
|
||||
ptr = argv[2];
|
||||
prio = atoi(argv[3]);
|
||||
|
||||
|
||||
if ((mqd = mq_open(argv[1], O_WRONLY)) == -1) {
|
||||
printf("open error");
|
||||
exit(0);
|
||||
}
|
||||
//ptr = calloc(len, sizeof(char));
|
||||
|
||||
mq_send(mqd, ptr, strlen(argv[2]), prio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dashboard_data_sync(int argc, char **argv, char NANO_UNUSED(*extra_arg))
|
||||
{
|
||||
mqd_t mqd;
|
||||
char buff[64];
|
||||
|
||||
srand((unsigned)time(NULL));
|
||||
if (argc != 1) {
|
||||
printf("usage:sync <type:post/cache> ");
|
||||
exit(0);
|
||||
}
|
||||
}
|
4
nanomq/apps/mq.h
Normal file
4
nanomq/apps/mq.h
Normal file
@ -0,0 +1,4 @@
|
||||
extern int mqcreate_debug(int argc, char **argv, char *extra_arg);
|
||||
extern int mqsend_debug(int argc, char **argv, char *extra_arg);
|
||||
extern int mqreceive_debug(int argc, char **argv, char *extra_arg);
|
||||
extern int dashboard_data_sync(int argc, char **argv, char *extra_arg);
|
301
nanomq/cmd.c
Normal file
301
nanomq/cmd.c
Normal file
@ -0,0 +1,301 @@
|
||||
|
||||
#include "include/nanomq.h"
|
||||
#include "include/cmd.h"
|
||||
#include "include/file.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
char *cmd_output_buff = NULL;
|
||||
int cmd_output_len = 0;
|
||||
|
||||
int cmd_run_status(const char *cmd)
|
||||
{
|
||||
int error, pipes[2], stderr_fd = -1, ret = 0;
|
||||
unsigned int sock_opts;
|
||||
|
||||
debug_msg("cmd = %s", cmd);
|
||||
/*file_append_string("/tmp/cmd.log", (char *)cmd);
|
||||
file_append_string("/tmp/cmd.log", "\n");*/
|
||||
|
||||
if (!cmd_output_buff)
|
||||
cmd_output_buff = malloc(CMD_BUFF_LEN);
|
||||
|
||||
if (!cmd_output_buff)
|
||||
return -1;
|
||||
|
||||
error = pipe(pipes);
|
||||
if (error < 0) {
|
||||
debug_msg("Warning - could not create a pipe to '%s': %s",
|
||||
cmd, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* save stderr */
|
||||
stderr_fd = dup(STDERR_FILENO);
|
||||
|
||||
/* connect the commands output with the pipe for later logging */
|
||||
dup2(pipes[1], STDERR_FILENO);
|
||||
close(pipes[1]);
|
||||
|
||||
error = system(cmd);
|
||||
|
||||
/* copy stderr back */
|
||||
dup2(stderr_fd, STDERR_FILENO);
|
||||
close(stderr_fd);
|
||||
|
||||
memset(cmd_output_buff, 0, CMD_BUFF_LEN);
|
||||
sock_opts = fcntl(pipes[0], F_GETFL, 0);
|
||||
fcntl(pipes[0], F_SETFL, sock_opts | O_NONBLOCK);
|
||||
cmd_output_len = read(pipes[0], cmd_output_buff, CMD_BUFF_LEN);
|
||||
|
||||
if (error < 0)
|
||||
ret = error;
|
||||
else if (WIFEXITED(error) && WEXITSTATUS(error) != 0)
|
||||
ret = WEXITSTATUS(error);
|
||||
|
||||
close(pipes[0]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cmd_run(const char *cmd)
|
||||
{
|
||||
int error, ret = 0;
|
||||
|
||||
error = cmd_run_status(cmd);
|
||||
|
||||
if (error != 0) {
|
||||
debug_msg("Warning - command '%s' returned an error", cmd);
|
||||
|
||||
if (cmd_output_len > 0)
|
||||
//debug_msg(" %s", cmd_output_buff);
|
||||
debug_msg("warning");
|
||||
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cmd_run_fd(int fd, const char *cmd)
|
||||
{
|
||||
int error, stderr_fd = -1, ret = 0;
|
||||
|
||||
debug_msg("fd = %i, cmd = %s", fd, cmd);
|
||||
/*file_append_string("/tmp/cmd.log", (char *)cmd);
|
||||
file_append_string("/tmp/cmd.log", "\n");*/
|
||||
|
||||
/* save stderr */
|
||||
stderr_fd = dup(STDERR_FILENO);
|
||||
|
||||
/* connect the commands output with the pipe for later logging */
|
||||
dup2(fd, STDERR_FILENO);
|
||||
|
||||
error = system(cmd);
|
||||
|
||||
/* copy stderr back */
|
||||
dup2(stderr_fd, STDERR_FILENO);
|
||||
close(stderr_fd);
|
||||
|
||||
if ((error < 0) || (WEXITSTATUS(error) != 0)) {
|
||||
debug_msg("Warning - command '%s' returned an error", cmd);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cmd_frun(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *cmd;
|
||||
int ret;
|
||||
|
||||
cmd = malloc(512);
|
||||
if (!cmd)
|
||||
return -1;
|
||||
|
||||
va_start(args, format);
|
||||
vsprintf(cmd, format, args);
|
||||
va_end(args);
|
||||
|
||||
ret = cmd_run(cmd);
|
||||
free(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cmd_frun_fd(int fd, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *cmd;
|
||||
int ret;
|
||||
|
||||
cmd = malloc(512);
|
||||
if (!cmd)
|
||||
return -1;
|
||||
|
||||
va_start(args, format);
|
||||
vsprintf(cmd, format, args);
|
||||
va_end(args);
|
||||
|
||||
ret = cmd_run_fd(fd, cmd);
|
||||
free(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cmd_pipe(const char *cmd)
|
||||
{
|
||||
int fd[2], ret;
|
||||
pid_t pid;
|
||||
|
||||
debug_msg("cmd_pipe: cmd = %s", cmd);
|
||||
ret = pipe(fd);
|
||||
|
||||
if (ret < 0) {
|
||||
debug_msg("cmd_pipe: could not create pipe to '%s': %s", cmd, strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
|
||||
switch (pid) {
|
||||
case -1:
|
||||
goto err;
|
||||
case 0:
|
||||
close(fd[1]);
|
||||
if (fd[0] != STDIN_FILENO) {
|
||||
if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
close(fd[0]);
|
||||
}
|
||||
signal(SIGINT, SIG_IGN);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
execl("/bin/sh", "/bin/sh", "-c", cmd, NULL);
|
||||
exit(0);
|
||||
default:
|
||||
close(fd[0]);
|
||||
return fd[1];
|
||||
}
|
||||
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cmd_fpipe(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *cmd;
|
||||
int ret;
|
||||
|
||||
cmd = malloc(512);
|
||||
if (!cmd)
|
||||
return -1;
|
||||
|
||||
va_start(args, format);
|
||||
vsprintf(cmd, format, args);
|
||||
va_end(args);
|
||||
|
||||
ret = cmd_pipe(cmd);
|
||||
free(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pid_t cmd_create_read_pipe(int *fd, const char *cmd, ...)
|
||||
{
|
||||
const char *cmd_run;
|
||||
char **args = NULL;
|
||||
int pipes[2];
|
||||
va_list ap;
|
||||
pid_t pid;
|
||||
char *str;
|
||||
int n;
|
||||
|
||||
va_start(ap, cmd);
|
||||
|
||||
if ((str = va_arg(ap, char *)) == NULL) {
|
||||
cmd_run = "/bin/sh";
|
||||
args = malloc(sizeof(char *) * 4);
|
||||
args[0] = "/bin/sh";
|
||||
args[1] = "-c";
|
||||
args[2] = (char *)cmd;
|
||||
args[3] = NULL;
|
||||
} else {
|
||||
cmd_run = cmd;
|
||||
args = malloc(sizeof(char *));
|
||||
args[0] = malloc(strlen(cmd) + 1);
|
||||
strcpy(args[0], cmd);
|
||||
n = 1;
|
||||
|
||||
do {
|
||||
args = realloc(args, sizeof(char *) * (n + 1));
|
||||
args[n] = malloc(strlen(str) + 1);
|
||||
strcpy(args[n], str);
|
||||
n++;
|
||||
} while ((str = va_arg(ap, char *)) != NULL);
|
||||
|
||||
args = realloc(args, sizeof(char *) * (n + 1));
|
||||
args[n] = NULL;
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
||||
if (pipe(pipes) < 0) {
|
||||
debug_msg("%s: count not create pipe to '%s' : %s",
|
||||
cmd, strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
|
||||
switch (pid) {
|
||||
case -1:
|
||||
goto err;
|
||||
case 0:
|
||||
close(pipes[0]);
|
||||
|
||||
if (pipes[1] != STDOUT_FILENO) {
|
||||
if (dup2(pipes[1], STDOUT_FILENO) != STDOUT_FILENO)
|
||||
exit(EXIT_FAILURE);
|
||||
close(pipes[1]);
|
||||
}
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
execv(cmd_run, args);
|
||||
free(args);
|
||||
|
||||
if (str)
|
||||
free(str);
|
||||
|
||||
exit(0);
|
||||
default:
|
||||
close(pipes[1]);
|
||||
*fd = dup(pipes[0]);
|
||||
|
||||
if(args)
|
||||
free(args);
|
||||
|
||||
if(str)
|
||||
free(str);
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void cmd_cleanup(void)
|
||||
{
|
||||
if (!cmd_output_buff)
|
||||
return;
|
||||
|
||||
free(cmd_output_buff);
|
||||
cmd_output_buff = NULL;
|
||||
}
|
6
nanomq/const_string.c
Normal file
6
nanomq/const_string.c
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
/***
|
||||
*
|
||||
*
|
||||
***/
|
||||
|
10
nanomq/emq_parser.c
Normal file
10
nanomq/emq_parser.c
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* static MQTT parser lib
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
536
nanomq/file.c
Normal file
536
nanomq/file.c
Normal file
@ -0,0 +1,536 @@
|
||||
|
||||
/***
|
||||
*
|
||||
***/
|
||||
|
||||
#include "include/nanomq.h"
|
||||
#include "include/file.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <mtd/mtd-user.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#define NG_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
|
||||
|
||||
static char fpath_tmp[100];
|
||||
|
||||
int file_trunc_to_zero(const char *fpath)
|
||||
{
|
||||
int fd;
|
||||
|
||||
debug_msg("fpath = %s\n", fpath);
|
||||
|
||||
fd = open(fpath, O_WRONLY | O_CREAT | O_TRUNC, NG_MODE);
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*return 1 if exists*/
|
||||
int file_exists(const char *fpath)
|
||||
{
|
||||
struct stat st;
|
||||
int ret;
|
||||
|
||||
ret = stat(fpath, &st) == 0 ? 1 : 0;
|
||||
debug_msg("%s: %i", fpath, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int file_is_symlink(const char *fpath)
|
||||
{
|
||||
int ret;
|
||||
struct stat st;
|
||||
|
||||
ret = lstat(fpath, &st);
|
||||
if (ret != 0)
|
||||
return 0;
|
||||
|
||||
return S_ISLNK(st.st_mode);
|
||||
}
|
||||
|
||||
int file_size(const char *fpath)
|
||||
{
|
||||
int ret;
|
||||
struct stat st;
|
||||
|
||||
if (!file_exists(fpath))
|
||||
return 0;
|
||||
|
||||
ret = stat(fpath, &st);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
|
||||
return st.st_size;
|
||||
}
|
||||
|
||||
int file_create_symlink(const char *file_path, const char *link_path)
|
||||
{
|
||||
debug_msg("%s => %s", file_path, link_path);
|
||||
return symlink(file_path, link_path);
|
||||
}
|
||||
|
||||
int file_read_int(const char *fpath_fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char buff[10];
|
||||
int fd, ret = 0;
|
||||
|
||||
va_start(args, fpath_fmt);
|
||||
vsnprintf(fpath_tmp, sizeof(fpath_tmp), fpath_fmt, args);
|
||||
va_end(args);
|
||||
|
||||
if (!file_exists(fpath_tmp))
|
||||
goto out;
|
||||
|
||||
fd = open(fpath_tmp, O_RDONLY);
|
||||
if (fd < 0)
|
||||
goto out;
|
||||
|
||||
ret = read(fd, buff, sizeof(buff));
|
||||
if (ret < 0)
|
||||
goto close;
|
||||
|
||||
ret = strtol(buff, (char **)NULL, 10);
|
||||
debug_msg("fpath = %s, pid = %d", fpath_tmp, ret);
|
||||
|
||||
close:
|
||||
close(fd);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int file_read_string(const char *fpath, char *buff, int buff_len)
|
||||
{
|
||||
int fd, ret = 0;
|
||||
|
||||
if (!file_exists(fpath))
|
||||
goto out;
|
||||
|
||||
fd = open(fpath, O_RDONLY);
|
||||
if (fd < 0)
|
||||
goto out;
|
||||
|
||||
ret = read(fd, buff, buff_len);
|
||||
if (ret < 0)
|
||||
goto close;
|
||||
|
||||
if (ret > 0)
|
||||
buff[ret - 1] = '\0';
|
||||
|
||||
debug_msg("fpath = %s, string = %s", fpath, buff);
|
||||
|
||||
close:
|
||||
close(fd);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int file_delete(const char *fpath)
|
||||
{
|
||||
if (!fpath)
|
||||
return 0;
|
||||
|
||||
debug_msg("%s", fpath);
|
||||
return unlink(fpath);
|
||||
}
|
||||
|
||||
int file_create_dir(const char *fpath)
|
||||
{
|
||||
char *last_slash = NULL, *fpath_edit = NULL;
|
||||
int ret = -1;
|
||||
|
||||
debug_msg("dir = %s", fpath);
|
||||
|
||||
if (fpath[strlen(fpath) - 1] != '/') {
|
||||
fpath_edit = malloc(strlen(fpath) + 1);
|
||||
if (!fpath_edit)
|
||||
return -1;
|
||||
|
||||
strncpy(fpath_edit, fpath, strlen(fpath) + 1);
|
||||
fpath_edit[strlen(fpath)] = '\0';
|
||||
|
||||
last_slash = strrchr(fpath_edit, '/');
|
||||
|
||||
/* not a single slash in the string ? */
|
||||
if (!last_slash)
|
||||
goto out;
|
||||
|
||||
*last_slash = '\0';
|
||||
fpath = fpath_edit;
|
||||
}
|
||||
|
||||
debug_msg("mkdir = %s", fpath);
|
||||
ret = mkdir(fpath, 0777);
|
||||
out:
|
||||
free(fpath_edit);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int file_write_int(int val, const char *fpath_fmt, ...)
|
||||
{
|
||||
int fd;
|
||||
va_list args;
|
||||
char buff[10], buff_len;
|
||||
|
||||
if (!fpath_fmt)
|
||||
goto out;
|
||||
|
||||
va_start(args, fpath_fmt);
|
||||
vsnprintf(fpath_tmp, sizeof(fpath_tmp), fpath_fmt, args);
|
||||
va_end(args);
|
||||
|
||||
debug_msg("fpath = %s, int = %i", fpath_tmp, val);
|
||||
|
||||
buff_len = sprintf(buff, "%i\n", val);
|
||||
|
||||
fd = open(fpath_tmp, O_CREAT | O_WRONLY | O_TRUNC, NG_MODE);
|
||||
if (fd < 0) {
|
||||
debug_msg("Error - can't open file '%s' to write pid: %s",
|
||||
fpath_tmp, strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
write(fd, buff, buff_len);
|
||||
close(fd);
|
||||
return 1;
|
||||
|
||||
out:
|
||||
return 0;
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int file_write_string(const char *fpath, const char *string)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (!fpath)
|
||||
goto out;
|
||||
|
||||
debug_msg("fpath = %s, string = '%s'", fpath, string);
|
||||
|
||||
fd = open(fpath, O_CREAT | O_WRONLY | O_TRUNC, NG_MODE);
|
||||
if (fd < 0) {
|
||||
debug_msg("Error - can't open file '%s' to write string: %s",
|
||||
fpath, strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
write(fd, string, strlen(string));
|
||||
close(fd);
|
||||
return 1;
|
||||
|
||||
out:
|
||||
return 0;
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int file_append_string(const char *fpath, const char *string_fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char string[100];
|
||||
int fd;
|
||||
|
||||
if (!fpath)
|
||||
goto out;
|
||||
|
||||
debug_msg("string_fmt = %s", string_fmt);
|
||||
|
||||
va_start(args, string_fmt);
|
||||
vsnprintf(string, sizeof(string), string_fmt, args);
|
||||
string[sizeof(string)-1] = '\0';
|
||||
va_end(args);
|
||||
debug_msg("fpath = %s, string = %s", fpath, string);
|
||||
|
||||
fd = open(fpath, O_CREAT | O_WRONLY | O_APPEND, NG_MODE);
|
||||
if (fd < 0) {
|
||||
debug_msg("Error - can't open file '%s' to append string: '%s'",
|
||||
fpath, strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
write(fd, string, strlen(string));
|
||||
close(fd);
|
||||
return 1;
|
||||
|
||||
out:
|
||||
return 0;
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *file_find_line(const char *fpath, const char *string)
|
||||
{
|
||||
char *line_ptr = NULL, *ptr;
|
||||
FILE *fd;
|
||||
size_t len = 0;
|
||||
|
||||
debug_msg("fpath = %s, string = %s", fpath, string);
|
||||
|
||||
if (!fpath)
|
||||
goto out;
|
||||
|
||||
if (!string)
|
||||
goto out;
|
||||
|
||||
fd = fopen(fpath, "r");
|
||||
if (!fd)
|
||||
goto out;
|
||||
|
||||
while (getline(&line_ptr, &len, fd) != -1) {
|
||||
ptr = strcasestr(line_ptr, string);
|
||||
|
||||
if (!ptr)
|
||||
continue;
|
||||
|
||||
goto found;
|
||||
}
|
||||
|
||||
free(line_ptr);
|
||||
fclose(fd);
|
||||
out:
|
||||
return NULL;
|
||||
|
||||
found:
|
||||
fclose(fd);
|
||||
return line_ptr;
|
||||
}
|
||||
|
||||
int file_read_symlink_target(const char *fpath, char *buff, int buff_len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!file_is_symlink(fpath))
|
||||
return -1;
|
||||
|
||||
memset(buff, 0, buff_len);
|
||||
ret = readlink(fpath, buff, buff_len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
debug_msg("file %s links to %s", fpath, buff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int file_delete_symlink_target(const char *fpath)
|
||||
{
|
||||
int ret;
|
||||
char path_buff[100];
|
||||
|
||||
ret = file_read_symlink_target(fpath, path_buff, sizeof(path_buff));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
debug_msg("file %s", path_buff);
|
||||
return file_delete(path_buff);
|
||||
}
|
||||
|
||||
int file_is_directory(const char *fpath)
|
||||
{
|
||||
int ret;
|
||||
struct stat st;
|
||||
|
||||
ret = lstat(fpath, &st);
|
||||
if (ret != 0)
|
||||
return 0;
|
||||
|
||||
debug_msg("fpath = %s, is_directory = %d", fpath, S_ISDIR(st.st_mode));
|
||||
return S_ISDIR(st.st_mode);
|
||||
}
|
||||
|
||||
int file_read_bin(const char *fpath, unsigned char **buff,
|
||||
unsigned int offset, unsigned int length)
|
||||
{
|
||||
int fd, ret = 0;
|
||||
|
||||
if (!file_exists(fpath))
|
||||
goto out;
|
||||
|
||||
fd = open(fpath, O_RDONLY);
|
||||
if (fd < 0)
|
||||
goto out;
|
||||
|
||||
*buff = malloc(length + 1);
|
||||
if (!*buff)
|
||||
goto close;
|
||||
|
||||
lseek(fd, offset, SEEK_SET);
|
||||
|
||||
ret = read(fd, *buff, length);
|
||||
if (ret < 0)
|
||||
goto close;
|
||||
|
||||
/*if (ret > 1)
|
||||
*buff[ret - 1] = '\0';*/
|
||||
debug_msg("fpath = %s, offset = %u, length = %u", fpath, offset,
|
||||
length);
|
||||
|
||||
close:
|
||||
close(fd);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned int file_mtd_size_get(const char *fpath)
|
||||
{
|
||||
mtd_info_t mtd_info;
|
||||
unsigned int res = 0;
|
||||
int fd, ret;
|
||||
|
||||
debug_msg("fpath = %s", fpath);
|
||||
|
||||
if (!fpath)
|
||||
goto out;
|
||||
|
||||
fd = open(fpath, O_RDONLY);
|
||||
if (fd < 0)
|
||||
goto out;
|
||||
|
||||
ret = ioctl(fd, MEMGETINFO, &mtd_info);
|
||||
if (ret < 0)
|
||||
goto out_close;
|
||||
|
||||
res = mtd_info.size;
|
||||
|
||||
out_close:
|
||||
close(fd);
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
int file_mtd_write(const char *fpath, unsigned char *buff, unsigned int buff_len)
|
||||
{
|
||||
mtd_info_t mtd_info;
|
||||
erase_info_t ei;
|
||||
unsigned int res = 0;
|
||||
int fd, ret;
|
||||
|
||||
debug_msg("fpath = %s", fpath);
|
||||
|
||||
if (!fpath)
|
||||
goto out;
|
||||
|
||||
fd = open(fpath, O_RDWR);
|
||||
if (fd < 0)
|
||||
goto out;
|
||||
|
||||
ret = ioctl(fd, MEMGETINFO, &mtd_info);
|
||||
if (ret < 0)
|
||||
goto out_close;
|
||||
|
||||
ei.length = mtd_info.erasesize;
|
||||
|
||||
for (ei.start = 0; ei.start < mtd_info.size; ei.start += mtd_info.erasesize) {
|
||||
ioctl(fd, MEMUNLOCK, &ei);
|
||||
ioctl(fd, MEMERASE, &ei);
|
||||
}
|
||||
|
||||
res = write(fd, buff, buff_len);
|
||||
|
||||
out_close:
|
||||
close(fd);
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
int file_truncr_to_sep(const char *fpath, char *separator)
|
||||
{
|
||||
int fd, read_len;
|
||||
FILE *fd_tmp;
|
||||
char *line_ptr = NULL;
|
||||
size_t line_len = 0, trunc_len = 0, trunc_len_tmp = 0;
|
||||
|
||||
debug_msg("fpath = %s, separator = %s", fpath, separator);
|
||||
|
||||
fd_tmp = fopen(fpath, "r");
|
||||
if (!fd_tmp)
|
||||
goto write_sep;
|
||||
|
||||
while ((read_len = getline(&line_ptr, &line_len, fd_tmp)) != -1) {
|
||||
|
||||
if (strncmp(line_ptr, separator, strlen(separator)) == 0) {
|
||||
trunc_len += trunc_len_tmp;
|
||||
trunc_len_tmp = 0;
|
||||
}
|
||||
|
||||
trunc_len_tmp += read_len;
|
||||
}
|
||||
|
||||
fclose(fd_tmp);
|
||||
free(line_ptr);
|
||||
|
||||
write_sep:
|
||||
fd = open(fpath, O_RDWR | O_CREAT, NG_MODE);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
ftruncate(fd, trunc_len);
|
||||
lseek(fd, trunc_len, SEEK_SET);
|
||||
dprintf(fd, "%s\n", separator);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int file_extract_int(const char *fpath)
|
||||
{
|
||||
char buff[16], *ptr;
|
||||
int ret = 0;
|
||||
|
||||
if (!file_exists(fpath))
|
||||
goto out;
|
||||
|
||||
file_read_string(fpath, buff, sizeof(buff));
|
||||
|
||||
ptr = strpbrk(buff, "0123456789");
|
||||
if (!ptr)
|
||||
ptr = buff;
|
||||
|
||||
ret = strtol(ptr, (char **)NULL, 10);
|
||||
debug_msg("fpath = %s, int = %d", fpath, ret);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int file_append_int(const char *fpath, int value)
|
||||
{
|
||||
int fd;
|
||||
char buff[10], buff_len;
|
||||
|
||||
if (!fpath)
|
||||
goto out;
|
||||
|
||||
buff_len = sprintf(buff, "%i\n", value);
|
||||
|
||||
fd = open(fpath, O_CREAT | O_WRONLY | O_APPEND, NG_MODE);
|
||||
if (fd < 0) {
|
||||
debug_msg("Error - can't open file '%s' to append string: %s",
|
||||
fpath, strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
write(fd, buff, buff_len);
|
||||
close(fd);
|
||||
return 1;
|
||||
|
||||
out:
|
||||
return 0;
|
||||
error:
|
||||
return -1;
|
||||
}
|
1
nanomq/include/CMakeLists.txt
Normal file
1
nanomq/include/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
aux_source_directory(. DIR_LIB_SRCS)
|
19
nanomq/include/apps.h
Normal file
19
nanomq/include/apps.h
Normal file
@ -0,0 +1,19 @@
|
||||
|
||||
#define APP_NAME_MAX 25
|
||||
|
||||
struct nanomq_app {
|
||||
char name[APP_NAME_MAX];
|
||||
int (*dflt)(int argc, char **argv);
|
||||
int (*start)(int argc, char **argv);
|
||||
int (*stop)(int argc, char **argv);
|
||||
};
|
||||
|
||||
#define NANOMQ_APP(_name, _dflt, _start, _stop) \
|
||||
const struct nanomq_app nanomq_app_##_name = { \
|
||||
.name = #_name, \
|
||||
.dflt = _dflt, \
|
||||
.start = _start, \
|
||||
.stop = _stop, \
|
||||
}
|
||||
|
||||
extern const struct nanomq_app *edge_apps[];
|
27
nanomq/include/cmd.h
Normal file
27
nanomq/include/cmd.h
Normal file
@ -0,0 +1,27 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#define CMD_RUN(cmd) do { \
|
||||
ret = cmd_run(cmd); \
|
||||
if (ret < 0) \
|
||||
goto err; \
|
||||
} while (0)
|
||||
|
||||
#define CMD_FRUN(fcmd, arg...) do { \
|
||||
ret = cmd_frun(fcmd, ## arg); \
|
||||
if (ret < 0) \
|
||||
goto err; \
|
||||
} while (0)
|
||||
|
||||
#define CMD_BUFF_LEN 1024
|
||||
extern char *cmd_output_buff;
|
||||
extern int cmd_output_len;
|
||||
|
||||
extern int cmd_run(const char *cmd);
|
||||
extern int cmd_run_status(const char *cmd);
|
||||
extern int cmd_frun(const char *format, ...);
|
||||
extern int cmd_frun_fd(int fd, const char *format, ...);
|
||||
int cmd_pipe(const char *cmd);
|
||||
int cmd_fpipe(const char *format, ...);
|
||||
pid_t cmd_create_read_pipe(int *fd, const char *cmd, ...);
|
||||
void cmd_cleanup(void);
|
2
nanomq/include/const_strings.h
Normal file
2
nanomq/include/const_strings.h
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
extern const char tmp_example[];
|
26
nanomq/include/file.h
Normal file
26
nanomq/include/file.h
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
|
||||
int file_trunc_to_zero(const char *fpath);
|
||||
int file_exists(const char *fpath);
|
||||
int file_is_symlink(const char *fpath);
|
||||
int file_size(const char *fpath);
|
||||
int file_create_symlink(const char *file_path, const char *link_path);
|
||||
int file_read_int(const char *fpath_fmt, ...);
|
||||
int file_read_string(const char *fpath, char *buff, int buff_len);
|
||||
int file_delete(const char *fpath);
|
||||
int file_read_symlink_target(const char *fpath, char *buff, int buff_len);
|
||||
int file_delete_symlink_target(const char *fpath);
|
||||
int file_create_dir(const char *fpath);
|
||||
int file_write_int(int val, const char *fpath_fmt, ...);
|
||||
int file_write_string(const char *fpath, const char *string);
|
||||
int file_append_string(const char *fpath, const char *string_fmt, ...);
|
||||
char *file_find_line(const char *fpath, const char *string);
|
||||
int file_is_directory(const char *fpath);
|
||||
int file_read_bin(const char *fpath, unsigned char **buff,
|
||||
unsigned int offset, unsigned int length);
|
||||
unsigned int file_mtd_size_get(const char *fpath);
|
||||
int file_mtd_write(const char *fpath, unsigned char *buff,
|
||||
unsigned int buff_len);
|
||||
int file_truncr_to_sep(const char *fpath, char *separator);
|
||||
int file_append_int(const char *fpath, int value);
|
||||
int file_extract_int(const char *fpath);
|
136
nanomq/include/nanomq.h
Normal file
136
nanomq/include/nanomq.h
Normal file
@ -0,0 +1,136 @@
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#define DEBUG_FILE_PATH "/tmp/debug_nanomq.log"
|
||||
|
||||
// later expose on makefile
|
||||
/**/
|
||||
#if defined(NOLOG)
|
||||
#undef DEBUG_CONSOLE
|
||||
#undef DEBUG_FILE
|
||||
#undef DEBUG_SYSLOG
|
||||
#else
|
||||
#define DEBUG_CONSOLE
|
||||
#define DEBUG_FILE
|
||||
#define DEBUG_SYSLOG
|
||||
#endif
|
||||
|
||||
#undef LIBNANO_DEBUG
|
||||
#if defined(DEBUG_CONSOLE) || defined(DEBUG_FILE) || defined(DEBUG_SYSLOG)
|
||||
#define LIBNANO_DEBUG
|
||||
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <syslog.h>
|
||||
|
||||
static inline char *nanomq_time_str()
|
||||
{
|
||||
char *buff;
|
||||
time_t now;
|
||||
|
||||
now = time(NULL);
|
||||
buff = ctime(&now);
|
||||
if (!buff)
|
||||
return NULL;
|
||||
|
||||
if (buff[strlen(buff) - 1] == '\n')
|
||||
buff[strlen(buff) - 1] = '\0';
|
||||
|
||||
return buff;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG_CONSOLE)
|
||||
#define debug_console(fmt, arg...) do {\
|
||||
char *_t = nanomq_time_str();\
|
||||
fprintf(stderr, "%s %s: " fmt "\n", _t, __FUNCTION__, ## arg);\
|
||||
} while (0)
|
||||
#else
|
||||
#define debug_console(fmt, arg...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG_FILE)
|
||||
#define debug_file(fmt, arg...) do {\
|
||||
char *_t = nanomq_time_str();\
|
||||
FILE *file = fopen(DEBUG_FILE_PATH, "a");\
|
||||
fprintf(file, "%s [%i] %s: " fmt "\n", _t, getpid(), __FUNCTION__, ## arg);\
|
||||
fclose(file);\
|
||||
} while(0)
|
||||
#else
|
||||
#define debug_file(fmt, arg...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG_SYSLOG)
|
||||
#define debug_syslog(fmt, arg...) do {\
|
||||
openlog("nanomq", LOG_PID, LOG_DAEMON | LOG_EMERG);\
|
||||
syslog(0, "%s: " fmt, __FUNCTION__, ## arg);\
|
||||
closelog();\
|
||||
} while (0)
|
||||
#else
|
||||
#define debug_syslog(fmt, arg...) do { } while (0)
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(LIBNANO_DEBUG)
|
||||
#define debug_msg(fmt, arg...) do { \
|
||||
debug_console(fmt, ## arg); \
|
||||
debug_file(fmt, ## arg); \
|
||||
debug_syslog(fmt, ## arg); \
|
||||
} while (0)
|
||||
#else
|
||||
#define debug_msg(fmt, arg...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#define NNI_PUT16(ptr, u) \
|
||||
do { \
|
||||
(ptr)[0] = (uint8_t)(((uint16_t)(u)) >> 8u); \
|
||||
(ptr)[1] = (uint8_t)((uint16_t)(u)); \
|
||||
} while (0)
|
||||
|
||||
#define NNI_PUT32(ptr, u) \
|
||||
do { \
|
||||
(ptr)[0] = (uint8_t)(((uint32_t)(u)) >> 24u); \
|
||||
(ptr)[1] = (uint8_t)(((uint32_t)(u)) >> 16u); \
|
||||
(ptr)[2] = (uint8_t)(((uint32_t)(u)) >> 8u); \
|
||||
(ptr)[3] = (uint8_t)((uint32_t)(u)); \
|
||||
} while (0)
|
||||
|
||||
#define NNI_PUT64(ptr, u) \
|
||||
do { \
|
||||
(ptr)[0] = (uint8_t)(((uint64_t)(u)) >> 56u); \
|
||||
(ptr)[1] = (uint8_t)(((uint64_t)(u)) >> 48u); \
|
||||
(ptr)[2] = (uint8_t)(((uint64_t)(u)) >> 40u); \
|
||||
(ptr)[3] = (uint8_t)(((uint64_t)(u)) >> 32u); \
|
||||
(ptr)[4] = (uint8_t)(((uint64_t)(u)) >> 24u); \
|
||||
(ptr)[5] = (uint8_t)(((uint64_t)(u)) >> 16u); \
|
||||
(ptr)[6] = (uint8_t)(((uint64_t)(u)) >> 8u); \
|
||||
(ptr)[7] = (uint8_t)((uint64_t)(u)); \
|
||||
} while (0)
|
||||
|
||||
#define NNI_GET16(ptr, v) \
|
||||
v = (((uint16_t)((uint8_t)(ptr)[0])) << 8u) + \
|
||||
(((uint16_t)(uint8_t)(ptr)[1]))
|
||||
|
||||
#define NNI_GET32(ptr, v) \
|
||||
v = (((uint32_t)((uint8_t)(ptr)[0])) << 24u) + \
|
||||
(((uint32_t)((uint8_t)(ptr)[1])) << 16u) + \
|
||||
(((uint32_t)((uint8_t)(ptr)[2])) << 8u) + \
|
||||
(((uint32_t)(uint8_t)(ptr)[3]))
|
||||
|
||||
#define NNI_GET64(ptr, v) \
|
||||
v = (((uint64_t)((uint8_t)(ptr)[0])) << 56u) + \
|
||||
(((uint64_t)((uint8_t)(ptr)[1])) << 48u) + \
|
||||
(((uint64_t)((uint8_t)(ptr)[2])) << 40u) + \
|
||||
(((uint64_t)((uint8_t)(ptr)[3])) << 32u) + \
|
||||
(((uint64_t)((uint8_t)(ptr)[4])) << 24u) + \
|
||||
(((uint64_t)((uint8_t)(ptr)[5])) << 16u) + \
|
||||
(((uint64_t)((uint8_t)(ptr)[6])) << 8u) + \
|
||||
(((uint64_t)(uint8_t)(ptr)[7]))
|
||||
|
||||
|
||||
|
||||
#define NANO_UNUSED(x) (x)__attribute__((unused))
|
228
nanomq/include/packet.h
Normal file
228
nanomq/include/packet.h
Normal file
@ -0,0 +1,228 @@
|
||||
//
|
||||
// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
|
||||
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
|
||||
// Copyright 2019 Devolutions <info@devolutions.net>
|
||||
//
|
||||
// This software is supplied under the terms of the MIT License, a
|
||||
// copy of which should be located in the distribution where this
|
||||
// file was obtained (LICENSE.txt). A copy of the license may also be
|
||||
// found online at https://opensource.org/licenses/MIT.
|
||||
//
|
||||
//
|
||||
// The Struct to store mqtt_packet.
|
||||
|
||||
#ifndef MQTT_PACKET_H
|
||||
#define MQTT_PACKET_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct mqtt_string {
|
||||
char * str_body;
|
||||
int len;
|
||||
};
|
||||
typedef struct mqtt_string mqtt_string;
|
||||
|
||||
struct mqtt_string_node {
|
||||
struct mqtt_string_node * next;
|
||||
mqtt_string * it;
|
||||
};
|
||||
typedef struct mqtt_string_node mqtt_string_node;
|
||||
|
||||
struct mqtt_binary {
|
||||
unsigned char * str_body;
|
||||
int len;
|
||||
};
|
||||
typedef struct mqtt_binary mqtt_binary;
|
||||
|
||||
struct mqtt_str_pair {
|
||||
char * str_key; // key
|
||||
int len_key;
|
||||
char * str_value; // value
|
||||
int len_value;
|
||||
};
|
||||
typedef struct mqtt_str_pair mqtt_str_pair;
|
||||
|
||||
union Property_type{
|
||||
uint8_t u8;
|
||||
uint16_t u16;
|
||||
uint32_t u32;
|
||||
uint32_t varint;
|
||||
mqtt_binary binary;
|
||||
mqtt_string str;
|
||||
mqtt_str_pair strpair;
|
||||
};
|
||||
|
||||
struct property {
|
||||
uint8_t id;
|
||||
union Property_type value;
|
||||
struct property * next;
|
||||
};
|
||||
typedef struct property property;
|
||||
|
||||
struct mqtt_property {
|
||||
uint32_t len;
|
||||
uint32_t count;
|
||||
struct property * property;
|
||||
struct property * property_end;
|
||||
};
|
||||
typedef struct mqtt_property mqtt_property;
|
||||
|
||||
//variable header in mqtt_packet_subscribe
|
||||
struct topic_with_option {
|
||||
uint8_t qos: 2;
|
||||
uint8_t no_local: 1;
|
||||
uint8_t retain_as_publish: 1;
|
||||
uint8_t retain_handling: 4; // !!!!!TODO actually 2 bits
|
||||
mqtt_string topic_filter;
|
||||
uint8_t reason_code;
|
||||
};
|
||||
typedef struct topic_with_option topic_with_option;
|
||||
|
||||
struct topic_node {
|
||||
topic_with_option * it;
|
||||
struct topic_node * next;
|
||||
};
|
||||
typedef struct topic_node topic_node;
|
||||
|
||||
struct packet_subscribe {
|
||||
uint16_t packet_id;
|
||||
union Property_type sub_id;
|
||||
union Property_type user_property;
|
||||
topic_node * node; // storage topic_with_option
|
||||
};
|
||||
typedef struct packet_subscribe packet_subscribe;
|
||||
|
||||
struct packet_unsubscribe {
|
||||
uint16_t packet_id;
|
||||
union Property_type user_property;
|
||||
topic_node * node; // storage topic_with_option
|
||||
};
|
||||
typedef struct packet_unsubscribe packet_unsubscribe;
|
||||
|
||||
// variable header in mqtt_packet_connect
|
||||
struct mqtt_packet_connect {
|
||||
mqtt_string * proto_name;
|
||||
uint8_t proto_ver;
|
||||
bool is_bridge;
|
||||
bool clean_start;
|
||||
bool will_flag;
|
||||
uint8_t will_qos;
|
||||
bool will_retain;
|
||||
uint16_t keep_alive;
|
||||
mqtt_property * property;
|
||||
bool has_username;
|
||||
bool has_password;
|
||||
};
|
||||
|
||||
struct mqtt_payload_connect {
|
||||
mqtt_string * client_id; // 1-23 bytes[0-9a-zA-Z]
|
||||
mqtt_property * will_property; //app msg included
|
||||
mqtt_string * will_topic;
|
||||
mqtt_binary * will_payload;
|
||||
mqtt_string * username;
|
||||
mqtt_binary * password; //
|
||||
};
|
||||
|
||||
//variable header in mqtt_packet_connack
|
||||
struct mqtt_packet_connack {
|
||||
bool session_present;
|
||||
uint8_t reason_code;
|
||||
struct mqtt_property * property;
|
||||
};
|
||||
|
||||
//struct mqtt_payload_connack {} = NULL;
|
||||
|
||||
//variable header in mqtt_packet_publish
|
||||
struct mqtt_packet_publish {
|
||||
mqtt_string * topic;
|
||||
uint16_t packet_id;
|
||||
mqtt_property * property;
|
||||
};
|
||||
|
||||
struct mqtt_payload_publish {
|
||||
mqtt_binary * msg;
|
||||
};
|
||||
|
||||
//variable header in mqtt_apcket_puback
|
||||
struct mqtt_packet_puback {
|
||||
uint16_t packet_id;
|
||||
uint8_t reason_code;
|
||||
struct mqtt_property * property;
|
||||
};
|
||||
|
||||
//struct mqtt_payload_puback {} = NULL;
|
||||
|
||||
//variable header in mqtt_packet_unsubscribe
|
||||
struct mqtt_packet_unsubscribe {
|
||||
uint16_t packet_id;
|
||||
struct mqtt_property * property;
|
||||
};
|
||||
|
||||
struct mqtt_payload_unsubscribe {
|
||||
struct mqtt_string_node * topic_filter;
|
||||
int count;
|
||||
};
|
||||
|
||||
//variable header in mqtt_packet_unsuback
|
||||
struct mqtt_packet_unsuback {
|
||||
uint16_t packet_id;
|
||||
struct mqtt_property * property;
|
||||
};
|
||||
|
||||
struct mqtt_payload_unsuback {
|
||||
mqtt_binary * reason_code_list; //each byte->topic_filter in order
|
||||
};
|
||||
|
||||
// variable header in mqtt_packet_disconnect
|
||||
struct mqtt_packet_disconnect {
|
||||
uint8_t reason_code;
|
||||
struct mqtt_property * property;
|
||||
};
|
||||
|
||||
// struct mqtt_payload_disconnect {} = NULL;
|
||||
|
||||
//variable header in mqtt_packet_auth
|
||||
struct mqtt_packet_auth {
|
||||
uint8_t auth_reason_code;
|
||||
struct mqtt_property * property;
|
||||
};
|
||||
|
||||
// struct mqtt_payload_auth {} = NULL;
|
||||
|
||||
// typedef struct mqtt_packet_header mqtt_packet_header;
|
||||
|
||||
typedef struct mqtt_packet_connect mqtt_packet_connect;
|
||||
typedef struct mqtt_packet_connack mqtt_packet_connack;
|
||||
typedef struct mqtt_packet_publish mqtt_packet_publish;
|
||||
typedef struct mqtt_packet_puback mqtt_packet_puback;
|
||||
typedef struct mqtt_packet_unsubscribe mqtt_packet_unsubscribe;
|
||||
typedef struct mqtt_packet_unsuback mqtt_packet_unsuback;
|
||||
typedef struct mqtt_packet_disconnect mqtt_packet_disconnect;
|
||||
typedef struct mqtt_packet_auth mqtt_packet_auth;
|
||||
|
||||
typedef struct mqtt_payload_connect mqtt_payload_connect;
|
||||
typedef struct mqtt_payload_publish mqtt_payload_publish;
|
||||
typedef struct mqtt_payload_unsubscribe mqtt_payload_unsubscribe;
|
||||
typedef struct mqtt_payload_unsuback mqtt_payload_unsuback;
|
||||
|
||||
/*
|
||||
// ctx of subscribe
|
||||
struct ctx_sub {
|
||||
mqtt_string id; // client id
|
||||
// properties
|
||||
union Property_type sub_id;
|
||||
union Property_type user_property;
|
||||
// topic with option
|
||||
struct topic_with_option * topic_option;
|
||||
|
||||
// connect info
|
||||
// struct ctx_connect * ctx_con;
|
||||
};
|
||||
typedef struct ctx_sub ctx_sub;
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
6
nanomq/include/process.h
Normal file
6
nanomq/include/process.h
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
int process_is_alive(int pid);
|
||||
int process_send_signal(int pid, int signal);
|
||||
int pidgrp_send_signal(int pid, int signal);
|
||||
int process_daemonize(void);
|
||||
int process_create_child(int(*child_run)(void *), void *data);
|
17
nanomq/include/property_handle.h
Normal file
17
nanomq/include/property_handle.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef MQTT_PROPERTY_HANDLE_H
|
||||
#define MQTT_PROPERTY_HANDLE_H
|
||||
|
||||
#include <string.h>
|
||||
#include <nng/nng.h>
|
||||
#include "include/packet.h"
|
||||
|
||||
int type_of_variable_property(uint8_t id);
|
||||
void property_list_init(struct mqtt_property * list);
|
||||
int property_list_insert(struct mqtt_property * list, uint8_t id, uint8_t * bin);
|
||||
int property_list_free(struct mqtt_property * list);
|
||||
struct property * property_list_head(struct mqtt_property * list);
|
||||
struct property * property_list_end(struct mqtt_property * list);
|
||||
struct property * property_list_get_element(struct mqtt_property * list, int pos);
|
||||
struct property * property_list_find_element(struct mqtt_property * list, uint8_t id);
|
||||
|
||||
#endif
|
124
nanomq/include/pub_handler.h
Normal file
124
nanomq/include/pub_handler.h
Normal file
@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Created by Alvin on 2020/7/25.
|
||||
*/
|
||||
|
||||
#ifndef NANOMQ_PUB_HANDLER_H
|
||||
#define NANOMQ_PUB_HANDLER_H
|
||||
|
||||
#include <nng/nng.h>
|
||||
#include <apps/broker.h>
|
||||
#include "nng/protocol/mqtt/mqtt.h"
|
||||
|
||||
#define DISTRIBUTE_DIFF_MSG 1
|
||||
|
||||
typedef uint32_t variable_integer;
|
||||
|
||||
struct variable_string {
|
||||
uint32_t str_len;
|
||||
char *str_body;
|
||||
};
|
||||
|
||||
struct variable_binary {
|
||||
uint32_t data_len;
|
||||
uint8_t *data;
|
||||
};
|
||||
|
||||
//MQTT Fixed header
|
||||
struct fixed_header {
|
||||
//flag_bits
|
||||
uint8_t retain: 1;
|
||||
uint8_t qos: 2;
|
||||
uint8_t dup: 1;
|
||||
//packet_types
|
||||
mqtt_control_packet_types packet_type: 4;
|
||||
//remaining length
|
||||
uint32_t remain_len;
|
||||
};
|
||||
|
||||
struct property_u8 {
|
||||
bool has_value; //false: no value;
|
||||
uint8_t value;
|
||||
};
|
||||
|
||||
struct property_u16 {
|
||||
bool has_value; //false: no value;
|
||||
uint16_t value;
|
||||
};
|
||||
|
||||
struct property_u32 {
|
||||
bool has_value; //false: no value;
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
|
||||
//Special for publish message data structure
|
||||
union property_content {
|
||||
struct {
|
||||
struct property_u8 payload_fmt_indicator;
|
||||
struct property_u32 msg_expiry_interval;
|
||||
struct property_u16 topic_alias;
|
||||
struct variable_string response_topic;
|
||||
struct variable_binary correlation_data;
|
||||
struct variable_string user_property;
|
||||
struct property_u32 subscription_identifier;
|
||||
struct variable_string content_type;
|
||||
} publish;
|
||||
struct {
|
||||
struct variable_string reason_string;
|
||||
struct variable_string user_property;
|
||||
} pub_arrc, puback, pubrec, pubrel, pubcomp;
|
||||
};
|
||||
|
||||
//Properties
|
||||
struct properties {
|
||||
uint32_t len; //property length, exclude itself,variable byte integer;
|
||||
// struct property prop_content[PUBLISH_PROPERTIES_TOTAL];
|
||||
union property_content content;
|
||||
};
|
||||
|
||||
|
||||
//MQTT Variable header
|
||||
union variable_header {
|
||||
struct {
|
||||
uint16_t packet_identifier;
|
||||
struct variable_string topic_name;
|
||||
struct properties properties;
|
||||
} publish;
|
||||
|
||||
struct {
|
||||
uint16_t packet_identifier;
|
||||
reason_code reason_code: 8;
|
||||
struct properties properties;
|
||||
} pub_arrc, puback, pubrec, pubrel, pubcomp;
|
||||
};
|
||||
|
||||
|
||||
struct mqtt_payload {
|
||||
uint8_t *payload;
|
||||
uint32_t payload_len;
|
||||
};
|
||||
|
||||
struct pub_packet_struct {
|
||||
struct fixed_header fixed_header;
|
||||
union variable_header variable_header;
|
||||
struct mqtt_payload payload_body;
|
||||
|
||||
};
|
||||
|
||||
struct pipe_nng_msg {
|
||||
uint32_t pipe;
|
||||
uint32_t index;
|
||||
uint8_t qos;
|
||||
nng_msg *msg; //nng_msg
|
||||
};
|
||||
|
||||
typedef void (*transmit_msgs)(nng_msg *, emq_work *, uint32_t *);
|
||||
typedef void (*handle_client)(struct client *sub_client, void **pipes, uint32_t *total, void *packet);
|
||||
|
||||
void handle_pub(emq_work *work, nng_msg *send_msg, void **pipes, transmit_msgs tx_msgs);
|
||||
bool encode_pub_message(nng_msg *dest_msg, struct pub_packet_struct *dest_pub_packet, const emq_work *work);
|
||||
reason_code decode_pub_message(emq_work *work);
|
||||
void foreach_client(struct clients *sub_clients, void **pipe_content, uint32_t *totals, void *packet,
|
||||
handle_client handle_cb);
|
||||
|
||||
#endif //NNG_PUB_HANDLER_H
|
14
nanomq/include/subscribe_handle.h
Normal file
14
nanomq/include/subscribe_handle.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef MQTT_SUBSCRIBE_HANDLE_H
|
||||
#define MQTT_SUBSCRIBE_HANDLE_H
|
||||
|
||||
#include <nng/nng.h>
|
||||
#include "include/packet.h"
|
||||
#include "apps/broker.h"
|
||||
|
||||
uint8_t decode_sub_message(nng_msg *, packet_subscribe *);
|
||||
uint8_t encode_suback_message(nng_msg *, packet_subscribe *);
|
||||
uint8_t sub_ctx_handle(emq_work *);
|
||||
void destroy_sub_ctx(void *, char *);
|
||||
// uint8_t subscribe_handle(nng_msg *);
|
||||
|
||||
#endif
|
13
nanomq/include/unsubscribe_handle.h
Normal file
13
nanomq/include/unsubscribe_handle.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef MQTT_UNSUBSCRIBE_HANDLE_H
|
||||
#define MQTT_UNSUBSCRIBE_HANDLE_H
|
||||
|
||||
#include <nng/nng.h>
|
||||
#include "include/packet.h"
|
||||
#include "apps/broker.h"
|
||||
|
||||
uint8_t decode_unsub_message(nng_msg *, packet_unsubscribe *);
|
||||
uint8_t encode_unsuback_message(nng_msg *, packet_unsubscribe *);
|
||||
uint8_t unsub_ctx_handle(emq_work *);
|
||||
|
||||
#endif // MQTT_UNSUBSCRIBE_HANDLE_H
|
||||
|
5
nanomq/include/version.h
Normal file
5
nanomq/include/version.h
Normal file
@ -0,0 +1,5 @@
|
||||
#define FW_EV_VER_MAJOR 6
|
||||
#define FW_EV_VER_MINOR 3
|
||||
#define FW_EV_VER_PATCH 0
|
||||
#define FW_EV_VER_ID_SHORT "3"
|
||||
#define FW_EV_VER_ID_LONG "100"
|
158
nanomq/nanomq.c
Normal file
158
nanomq/nanomq.c
Normal file
@ -0,0 +1,158 @@
|
||||
#include "include/apps.h"
|
||||
#include "include/version.h"
|
||||
#include "include/process.h"
|
||||
#include "include/cmd.h"
|
||||
#include "include/const_strings.h"
|
||||
#include "include/nanomq.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#define NANO_APP_NAME "nanomq"
|
||||
#define NANO_BRAND "EMQ X Edge Computing Kit"
|
||||
|
||||
#define NANO_DEBUG
|
||||
|
||||
static void print_version(void)
|
||||
{
|
||||
printf("%s v.01-%s\n", NANO_BRAND, FW_EV_VER_ID_SHORT);
|
||||
printf("Copyright (C) 2012-2020 EMQ X Jaylin.\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int print_avail_apps(void)
|
||||
{
|
||||
#if defined(NANO_DEBUG)
|
||||
const struct nanomq_app **nano_app;
|
||||
|
||||
printf("available applications:\n");
|
||||
|
||||
for (nano_app = edge_apps; *nano_app; ++nano_app)
|
||||
printf(" * %s\n", (*nano_app)->name);
|
||||
#endif
|
||||
print_version();
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if !defined(DEBUG_TRACE)
|
||||
static int check_trace(char *name)
|
||||
{
|
||||
int pid, traced;
|
||||
|
||||
switch(pid = fork()) {
|
||||
case 0:
|
||||
pid = getppid();
|
||||
traced = ptrace(PTRACE_ATTACH, pid, 0, 0);
|
||||
|
||||
if (!traced) {
|
||||
process_send_signal(pid, SIGCONT);
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
perror(name);
|
||||
process_send_signal(pid, SIGKILL);
|
||||
goto err;
|
||||
case -1:
|
||||
break;
|
||||
default:
|
||||
if (pid == waitpid(pid, 0, 0))
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
perror(name);
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
static int check_trace(char DASH_UNUSED(*name))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int handle_app(int res)
|
||||
{
|
||||
cmd_cleanup();
|
||||
return res;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const struct nanomq_app **nano_app;
|
||||
char *app_name;
|
||||
int ret;
|
||||
|
||||
ret = check_trace(argv[0]);
|
||||
if (ret < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if ((argc > 1) && (strlen(argv[1]) > 1) &&
|
||||
(argv[1][0] == '-') && (argv[1][1] == 'v')) {
|
||||
print_version();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
app_name = strrchr(argv[0], '/');
|
||||
debug_msg("argv %s %s app_name %s", argv[0],argv[1], app_name);
|
||||
app_name = (app_name ? app_name + 1 : argv[0]);
|
||||
|
||||
debug_msg("argv %s %s app_name %s", argv[0],argv[1], app_name);
|
||||
if (strncmp(app_name, NANO_APP_NAME, APP_NAME_MAX) == 0) {
|
||||
debug_msg("argc : %d", argc);
|
||||
if (argc == 1)
|
||||
return print_avail_apps();
|
||||
|
||||
app_name = argv[1];
|
||||
argv++;
|
||||
argc--;
|
||||
}
|
||||
|
||||
for (nano_app = edge_apps; *nano_app; ++nano_app)
|
||||
if (strncmp(app_name, (*nano_app)->name, APP_NAME_MAX) == 0)
|
||||
break;
|
||||
|
||||
if (!(*nano_app)) {
|
||||
printf("Error - the application '%s' was not found\n", app_name);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
if ((*nano_app)->dflt)
|
||||
return handle_app((*nano_app)->dflt(argc - 1, argv + 1));
|
||||
|
||||
printf("Error - not enough arguments to run %s\n",
|
||||
app_name);
|
||||
goto err_param;
|
||||
}
|
||||
|
||||
if ((strcmp(argv[1], "start") == 0) && (*nano_app)->start)
|
||||
return handle_app((*nano_app)->start(argc - 2, argv + 2));
|
||||
|
||||
if ((strcmp(argv[1], "stop") == 0) && (*nano_app)->stop)
|
||||
return handle_app((*nano_app)->stop(argc - 2, argv + 2));
|
||||
|
||||
if ((*nano_app)->dflt)
|
||||
return handle_app((*nano_app)->dflt(argc - 1, argv + 1));
|
||||
|
||||
printf("Error - unknown parameter: %s\n", argv[1]);
|
||||
|
||||
err_param:
|
||||
printf("Use one of the following parameters:\n");
|
||||
if ((*nano_app)->start)
|
||||
printf(" * start\n");
|
||||
if ((*nano_app)->stop)
|
||||
printf(" * stop\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
103
nanomq/process.c
Normal file
103
nanomq/process.c
Normal file
@ -0,0 +1,103 @@
|
||||
|
||||
#include "include/nanomq.h"
|
||||
|
||||
#include "include/process.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
|
||||
int process_is_alive(int pid)
|
||||
{
|
||||
if (pid < 1)
|
||||
return 0;
|
||||
|
||||
return kill(pid, 0) == 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
int process_send_signal(int pid, int signal)
|
||||
{
|
||||
if (pid < 1)
|
||||
return 0;
|
||||
|
||||
debug_msg("pid = %i, signal = %i", pid, signal);
|
||||
return kill(pid, signal);
|
||||
}
|
||||
|
||||
int pidgrp_send_signal(int pid, int signal)
|
||||
{
|
||||
pid_t gpid;
|
||||
|
||||
if (pid < 1)
|
||||
return 0;
|
||||
|
||||
gpid = getpgid(pid);
|
||||
if (gpid < 0) {
|
||||
debug_msg("pid = %i: unable to retrieve gpid: %s", pid,
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug_msg("pid = %i: gpid = %i, signal = %i", pid, gpid, signal);
|
||||
return kill(-gpid, signal);
|
||||
}
|
||||
|
||||
int process_daemonize(void)
|
||||
{
|
||||
int fd;
|
||||
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
return -1;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (setsid() == -1)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
/* Make certain we are not a session leader, or else we might reacquire
|
||||
* a controlling terminal
|
||||
*/
|
||||
if (fork())
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
chdir("/");
|
||||
|
||||
fd = open(_PATH_DEVNULL, O_RDWR, 0);
|
||||
|
||||
if (fd != -1) {
|
||||
dup2(fd, STDIN_FILENO);
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
dup2(fd, STDERR_FILENO);
|
||||
|
||||
if (fd > 2)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int process_create_child(int(*child_run)(void *), void *data)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
pid = fork();
|
||||
|
||||
switch (pid) {
|
||||
case -1:
|
||||
return -1;
|
||||
case 0:
|
||||
exit(child_run(data));
|
||||
default:
|
||||
return pid;
|
||||
}
|
||||
}
|
1005
nanomq/pub_handler.c
Normal file
1005
nanomq/pub_handler.c
Normal file
File diff suppressed because it is too large
Load Diff
266
nanomq/subscribe_handle.c
Normal file
266
nanomq/subscribe_handle.c
Normal file
@ -0,0 +1,266 @@
|
||||
#include <nng.h>
|
||||
#include <nanolib.h>
|
||||
#include <protocol/mqtt/mqtt_parser.h>
|
||||
#include <protocol/mqtt/mqtt.h>
|
||||
#include "include/nanomq.h"
|
||||
#include "include/subscribe_handle.h"
|
||||
|
||||
uint8_t decode_sub_message(nng_msg * msg, packet_subscribe * sub_pkt){
|
||||
uint8_t * variable_ptr;
|
||||
uint8_t * payload_ptr;
|
||||
int vpos = 0; // pos in variable
|
||||
int bpos = 0; // pos in payload
|
||||
|
||||
int len_of_varint = 0, len_of_property = 0, len_of_properties = 0;
|
||||
int len_of_str, len_of_topic;
|
||||
size_t remaining_len = nng_msg_remaining_len(msg);
|
||||
|
||||
bool version_v5 = false; // v3.1.1/v5
|
||||
uint8_t property_id;
|
||||
|
||||
topic_node * topic_node_t, * _topic_node;
|
||||
|
||||
// handle variable header
|
||||
variable_ptr = nng_msg_variable_ptr(msg);
|
||||
|
||||
NNI_GET16(variable_ptr + vpos, sub_pkt->packet_id);
|
||||
vpos += 2;
|
||||
|
||||
// Only Mqtt_v5 include property.
|
||||
if(version_v5){
|
||||
// length of property in varibale
|
||||
len_of_properties = get_var_integer(variable_ptr+vpos, &len_of_varint);
|
||||
vpos += len_of_varint;
|
||||
|
||||
// parse property in variable
|
||||
if(len_of_properties > 0){
|
||||
while(1){
|
||||
property_id = variable_ptr[vpos++];
|
||||
switch(property_id){
|
||||
case SUBSCRIPTION_IDENTIFIER:
|
||||
sub_pkt->sub_id.varint = get_var_integer(variable_ptr+vpos, &len_of_varint);
|
||||
vpos += len_of_varint;
|
||||
break;
|
||||
case USER_PROPERTY:
|
||||
// key
|
||||
len_of_str = get_utf8_str(&(sub_pkt->user_property.strpair.str_key), variable_ptr, &vpos);
|
||||
sub_pkt->user_property.strpair.len_key = len_of_str;
|
||||
// vpos += len_of_str;
|
||||
|
||||
// value
|
||||
len_of_str = get_utf8_str(&(sub_pkt->user_property.strpair.str_value), variable_ptr, &vpos);
|
||||
sub_pkt->user_property.strpair.len_value = len_of_str;
|
||||
// vpos += len_of_str;
|
||||
break;
|
||||
default:
|
||||
// avoid error
|
||||
if(vpos > remaining_len){
|
||||
debug_msg("ERROR_IN_LEN_VPOS");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug_msg("Remain_len: [%ld] packet_id : [%d]", remaining_len, sub_pkt->packet_id);
|
||||
// handle payload
|
||||
payload_ptr = nng_msg_payload_ptr(msg);
|
||||
|
||||
debug_msg("V:[%x %x %x %x] P:[%x %x %x %x].", variable_ptr[0], variable_ptr[1], variable_ptr[2], variable_ptr[3],
|
||||
payload_ptr[0], payload_ptr[1], payload_ptr[2], payload_ptr[3]);
|
||||
|
||||
topic_node_t = nng_alloc(sizeof(topic_node));
|
||||
topic_node_t->next = NULL;
|
||||
sub_pkt->node = topic_node_t;
|
||||
|
||||
while(1){
|
||||
topic_with_option * topic_option = nng_alloc(sizeof(topic_with_option));
|
||||
topic_node_t->it = topic_option;
|
||||
_topic_node = topic_node_t;
|
||||
|
||||
len_of_topic = get_utf8_str(&(topic_option->topic_filter.str_body), payload_ptr, &bpos); // len of topic filter
|
||||
if(len_of_topic != -1){
|
||||
topic_option->topic_filter.len = len_of_topic;
|
||||
}else {
|
||||
debug_msg("NOT utf-8 format string. ");
|
||||
return PROTOCOL_ERROR;
|
||||
}
|
||||
|
||||
debug_msg("Length of topic: %d topic_node: %x %x. ", len_of_topic, (uint8_t)(topic_option->topic_filter.str_body[0]), (uint8_t)(topic_option->topic_filter.str_body[1]));
|
||||
|
||||
memcpy(topic_option, payload_ptr+bpos, 1);
|
||||
|
||||
debug_msg("Bpos+Vpos: [%d] Remain_len:%ld.", bpos+vpos, remaining_len);
|
||||
if(++bpos < remaining_len - vpos){
|
||||
topic_node_t = nng_alloc(sizeof(topic_node));
|
||||
topic_node_t->next = NULL;
|
||||
_topic_node->next = topic_node_t;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t encode_suback_message(nng_msg * msg, packet_subscribe * sub_pkt){
|
||||
bool version_v5 = false;
|
||||
nng_msg_clear(msg);
|
||||
|
||||
uint8_t packet_id[2];
|
||||
uint8_t reason_code, cmd;
|
||||
uint32_t remaining_len;
|
||||
uint8_t varint[4];
|
||||
int len_of_varint;
|
||||
topic_node * node;
|
||||
|
||||
// handle variable header first
|
||||
NNI_PUT16(packet_id, sub_pkt->packet_id);
|
||||
if(nng_msg_append(msg, packet_id, 2) != 0){
|
||||
debug_msg("NNG_MSG_APPEND_ERROR");
|
||||
return PROTOCOL_ERROR;
|
||||
}
|
||||
|
||||
if(version_v5){ // add property in variable
|
||||
}
|
||||
|
||||
// handle payload
|
||||
node = sub_pkt->node;
|
||||
while(node){
|
||||
if(version_v5){
|
||||
}else{
|
||||
if(node->it->reason_code == 0x80){
|
||||
reason_code = 0x80;
|
||||
}else{
|
||||
reason_code = node->it->qos;
|
||||
}
|
||||
// MQTT_v3: 0x00-qos0 0x01-qos1 0x02-qos2 0x80-fail
|
||||
if(nng_msg_append(msg, (uint8_t *) &reason_code, 1) != 0){
|
||||
debug_msg("NNG_MSG_APPEND_ERROR");
|
||||
return PROTOCOL_ERROR;
|
||||
}
|
||||
}
|
||||
node = node->next;
|
||||
debug_msg("reason_code: [%x]", reason_code);
|
||||
}
|
||||
// handle fixed header
|
||||
cmd = CMD_SUBACK;
|
||||
if(nng_msg_header_append(msg, (uint8_t *) &cmd, 1) != 0){
|
||||
debug_msg("NNG_HEADER_APPEND_ERROR");
|
||||
return PROTOCOL_ERROR;
|
||||
}
|
||||
|
||||
remaining_len = (uint32_t)nng_msg_len(msg);
|
||||
len_of_varint = put_var_integer(varint, remaining_len);
|
||||
if(nng_msg_header_append(msg, varint, len_of_varint) != 0){
|
||||
debug_msg("NNG_MSG_APPEND_ERROR");
|
||||
return PROTOCOL_ERROR;
|
||||
}
|
||||
|
||||
debug_msg("remain: [%d] varint: [%d %d %d %d] len: [%d] packet_id: [%x %x]", remaining_len, varint[0], varint[1], varint[2], varint[3], len_of_varint, packet_id[0], packet_id[1]);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t sub_ctx_handle(emq_work * work){
|
||||
// generate ctx for each topic
|
||||
int count = 0;
|
||||
bool version_v5 = false;
|
||||
|
||||
topic_node * topic_node_t = work->sub_pkt->node;
|
||||
char * topic_str;
|
||||
|
||||
// insert ctx_sub into treeDB
|
||||
while(topic_node_t){
|
||||
struct topic_and_node *tan = nng_alloc(sizeof(struct topic_and_node));
|
||||
struct client * client = nng_alloc(sizeof(struct client));
|
||||
|
||||
//setting client
|
||||
client->id = (char *)conn_param_get_clentid((conn_param *)nng_msg_get_conn_param(work->msg));
|
||||
client->ctxt = work;
|
||||
client->next = NULL;
|
||||
|
||||
topic_str = (char *)nng_alloc(topic_node_t->it->topic_filter.len + 1);
|
||||
strncpy(topic_str, topic_node_t->it->topic_filter.str_body, topic_node_t->it->topic_filter.len);
|
||||
topic_str[topic_node_t->it->topic_filter.len] = '\0';
|
||||
debug_msg("topicLen: [%d] Body: [%s]", topic_node_t->it->topic_filter.len, (char *)topic_str);
|
||||
|
||||
char ** topic_queue = topic_parse(topic_str);
|
||||
// debug_msg("topic_queue: -%s -%s -%s -%s", *topic_queue, *(topic_queue+1), *(topic_queue+2), *(topic_queue+3));
|
||||
search_node(work->db, topic_queue, tan);
|
||||
|
||||
if(tan->topic){ // not contain the node
|
||||
add_node(tan, client);
|
||||
add_topic(client->id, topic_str);
|
||||
add_pipe_id(work->pid.id, client->id);
|
||||
struct topic_queue * q = get_topic(client->id);
|
||||
debug_msg("-----CHECKHASHTABLE----clientid:%s---topic:%s---pipeid:%d",
|
||||
client->id, q->topic, work->pid.id);
|
||||
}else{
|
||||
// not contain clientid
|
||||
if(tan->node->sub_client==NULL || check_client(tan->node, client->id)){
|
||||
add_topic(client->id, topic_str);
|
||||
add_pipe_id(work->pid.id, client->id);
|
||||
struct topic_queue * q = get_topic(client->id);
|
||||
// debug_msg("------CHECKHASHTABLE----clientid:%s---next-topic:%s",
|
||||
// client->id, q->next->topic);
|
||||
add_client(tan, client);
|
||||
// test
|
||||
search_node(work->db, topic_queue, tan);
|
||||
struct client * cli = tan->node->sub_client;
|
||||
while(cli){
|
||||
debug_msg("client: %s", cli->id);
|
||||
cli = cli->next;
|
||||
}
|
||||
}else{ // clientid already in hash
|
||||
work->sub_pkt->node->it->reason_code = 0x80;
|
||||
}
|
||||
}
|
||||
nng_free(tan, sizeof(struct topic_and_node));
|
||||
nng_free(topic_str, topic_node_t->it->topic_filter.len+1);
|
||||
topic_node_t = topic_node_t->next;
|
||||
}
|
||||
|
||||
// check treeDB
|
||||
print_db_tree(work->db);
|
||||
debug_msg("End of sub ctx handle. \n");
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
void destroy_sub_ctx(void * ctxt, char * target_topic){
|
||||
emq_work * work = ctxt;
|
||||
if(!work){
|
||||
return;
|
||||
}
|
||||
if(!work->sub_pkt){
|
||||
debug_msg("ERROR : ctx->sub is nil");
|
||||
return;
|
||||
}
|
||||
packet_subscribe * sub_pkt = work->sub_pkt;
|
||||
if(!(sub_pkt->node->it)){
|
||||
debug_msg("NOT FIND TOPIC");
|
||||
return;
|
||||
}
|
||||
topic_node * topic_node_t = sub_pkt->node;
|
||||
topic_node * before_topic_node = NULL;
|
||||
while(topic_node_t){
|
||||
if(!strncmp(topic_node_t->it->topic_filter.str_body, target_topic,
|
||||
topic_node_t->it->topic_filter.len)){
|
||||
debug_msg("FREE in topic_node [%s] in tree", topic_node_t->it->topic_filter.str_body);
|
||||
if(before_topic_node){
|
||||
before_topic_node->next = topic_node_t->next;
|
||||
}else{
|
||||
sub_pkt->node = topic_node_t->next;
|
||||
}
|
||||
nng_free(topic_node_t->it, sizeof(topic_with_option));
|
||||
nng_free(topic_node_t, sizeof(topic_node));
|
||||
break;
|
||||
}
|
||||
before_topic_node = topic_node_t;
|
||||
topic_node_t = topic_node_t->next;
|
||||
}
|
||||
|
||||
if(sub_pkt->node == NULL){
|
||||
nng_free(sub_pkt, sizeof(packet_subscribe));
|
||||
work->sub_pkt = NULL;
|
||||
}
|
||||
}
|
||||
|
199
nanomq/unsubscribe_handle.c
Normal file
199
nanomq/unsubscribe_handle.c
Normal file
@ -0,0 +1,199 @@
|
||||
#include <nng.h>
|
||||
#include <nanolib.h>
|
||||
#include <protocol/mqtt/mqtt_parser.h>
|
||||
#include <protocol/mqtt/mqtt.h>
|
||||
#include "include/nanomq.h"
|
||||
#include "include/subscribe_handle.h"
|
||||
#include "include/unsubscribe_handle.h"
|
||||
|
||||
uint8_t decode_unsub_message(nng_msg * msg, packet_unsubscribe * unsub_pkt){
|
||||
uint8_t * variable_ptr;
|
||||
uint8_t * payload_ptr;
|
||||
int vpos = 0; // pos in variable
|
||||
int bpos = 0; // pos in payload
|
||||
|
||||
int len_of_varint = 0, len_of_property = 0, len_of_properties = 0;
|
||||
int len_of_str, len_of_topic;
|
||||
size_t remaining_len = nng_msg_remaining_len(msg);
|
||||
|
||||
bool version_v5 = false; // v3.1.1/v5
|
||||
uint8_t property_id;
|
||||
|
||||
topic_node * topic_node_t, * _topic_node;
|
||||
|
||||
// handle varibale header
|
||||
variable_ptr = nng_msg_variable_ptr(msg);
|
||||
NNI_GET16(variable_ptr, unsub_pkt->packet_id);
|
||||
vpos += 2;
|
||||
|
||||
// Mqtt_v5 include property
|
||||
if(version_v5){
|
||||
// length of property in variable
|
||||
len_of_properties = get_var_integer(variable_ptr, &len_of_varint);
|
||||
vpos += len_of_varint;
|
||||
|
||||
if(len_of_properties > 0){
|
||||
while(1){
|
||||
property_id = variable_ptr[vpos];
|
||||
switch(property_id){
|
||||
case USER_PROPERTY:
|
||||
// key
|
||||
len_of_str = get_utf8_str(&(unsub_pkt->user_property.strpair.str_key), variable_ptr, &vpos);
|
||||
unsub_pkt->user_property.strpair.len_key = len_of_str;
|
||||
// value
|
||||
len_of_str = get_utf8_str(&(unsub_pkt->user_property.strpair.str_value), variable_ptr, &vpos);
|
||||
unsub_pkt->user_property.strpair.len_value = len_of_str;
|
||||
default:
|
||||
if(vpos > remaining_len){
|
||||
debug_msg("ERROR_IN_LEN_VPOS");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug_msg("Remain_len: [%ld] packet_id : [%d]", remaining_len, unsub_pkt->packet_id);
|
||||
|
||||
// handle payload
|
||||
payload_ptr = nng_msg_payload_ptr(msg);
|
||||
|
||||
debug_msg("V:[%x %x %x %x] P:[%x %x %x %x].", variable_ptr[0], variable_ptr[1], variable_ptr[2], variable_ptr[3],
|
||||
payload_ptr[0], payload_ptr[1], payload_ptr[2], payload_ptr[3]);
|
||||
|
||||
topic_node_t = nng_alloc(sizeof(topic_node));
|
||||
unsub_pkt->node = topic_node_t;
|
||||
topic_node_t->next = NULL;
|
||||
|
||||
while(1){
|
||||
topic_with_option * topic_option = nng_alloc(sizeof(topic_with_option));
|
||||
topic_node_t->it = topic_option;
|
||||
_topic_node = topic_node_t;
|
||||
|
||||
len_of_topic = get_utf8_str(&(topic_option->topic_filter.str_body), payload_ptr, &bpos); // len of topic filter
|
||||
if(len_of_topic != -1){
|
||||
topic_option->topic_filter.len = len_of_topic;
|
||||
}else {
|
||||
debug_msg("NOT utf-8 format string.");
|
||||
return PROTOCOL_ERROR;
|
||||
}
|
||||
|
||||
debug_msg("Topiclen: [%d]", len_of_topic);
|
||||
debug_msg("Bpos+Vpos: [%d] Remain_len:%ld.", bpos+vpos, remaining_len);
|
||||
if(bpos < remaining_len - vpos){
|
||||
topic_node_t = nng_alloc(sizeof(topic_node));
|
||||
topic_node_t->next = NULL;
|
||||
_topic_node->next = topic_node_t;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t encode_unsuback_message(nng_msg * msg, packet_unsubscribe * unsub_pkt){
|
||||
bool version_v5 = false;
|
||||
nng_msg_clear(msg);
|
||||
|
||||
uint8_t packet_id[2];
|
||||
uint8_t reason_code, cmd;
|
||||
uint32_t remaining_len;
|
||||
uint8_t varint[4];
|
||||
int len_of_varint;
|
||||
topic_node * node;
|
||||
|
||||
// handle variable header first
|
||||
NNI_PUT16(packet_id, unsub_pkt->packet_id);
|
||||
if(nng_msg_append(msg, packet_id, 2) != 0){
|
||||
debug_msg("NNG_MSG_APPEND_ERROR");
|
||||
return PROTOCOL_ERROR;
|
||||
}
|
||||
|
||||
if(version_v5){ // add property in variable
|
||||
}
|
||||
|
||||
// handle payload
|
||||
// no payload in mqtt_v3
|
||||
if(version_v5){
|
||||
node = unsub_pkt->node;
|
||||
while(node){
|
||||
reason_code = node->it->reason_code;
|
||||
nng_msg_append(msg, (uint8_t *) &reason_code, 1);
|
||||
node = node->next;
|
||||
debug_msg("reason_code: [%x]", reason_code);
|
||||
}
|
||||
}
|
||||
|
||||
// handle fixed header
|
||||
cmd = CMD_UNSUBACK;
|
||||
if(nng_msg_header_append(msg, (uint8_t *) &cmd, 1) != 0){
|
||||
debug_msg("NNG_HEADER_APPEND_ERROR");
|
||||
return PROTOCOL_ERROR;
|
||||
}
|
||||
|
||||
remaining_len = (uint32_t)nng_msg_len(msg);
|
||||
len_of_varint = put_var_integer(varint, remaining_len);
|
||||
if(nng_msg_header_append(msg, varint, len_of_varint) != 0){
|
||||
debug_msg("NNG_MSG_APPEND_ERROR");
|
||||
return PROTOCOL_ERROR;
|
||||
}
|
||||
|
||||
debug_msg("remain: [%d] varint: [%d %d %d %d] len: [%d] packet_id: [%x %x]", remaining_len, varint[0], varint[1], varint[2], varint[3], len_of_varint, packet_id[0], packet_id[1]);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t unsub_ctx_handle(emq_work * work){
|
||||
bool version_v5 = false;
|
||||
|
||||
topic_node * topic_node_t = work->unsub_pkt->node;
|
||||
char * topic_str;
|
||||
char * clientid;
|
||||
struct client * cli = NULL;
|
||||
|
||||
// delete ctx_unsub in treeDB
|
||||
while(topic_node_t){
|
||||
struct topic_and_node *tan = nng_alloc(sizeof(struct topic_and_node));
|
||||
clientid = (char *)conn_param_get_clentid((conn_param *)nng_msg_get_conn_param(work->msg));
|
||||
|
||||
// parse topic string
|
||||
topic_str = (char *)nng_alloc(topic_node_t->it->topic_filter.len + 1);
|
||||
strncpy(topic_str, topic_node_t->it->topic_filter.str_body, topic_node_t->it->topic_filter.len);
|
||||
topic_str[topic_node_t->it->topic_filter.len] = '\0';
|
||||
|
||||
debug_msg("finding client [%s] in topic [%s].", clientid, topic_str);
|
||||
|
||||
char ** topic_queue = topic_parse(topic_str);
|
||||
search_node(work->db, topic_queue, tan);
|
||||
|
||||
if(tan->topic == NULL){ // find the topic
|
||||
cli = del_client(tan, clientid);
|
||||
if(cli != NULL){
|
||||
// FREE clientinfo in dbtree and hashtable
|
||||
destroy_sub_ctx(cli->ctxt, topic_str);
|
||||
del_topic_one(clientid, topic_str);
|
||||
nng_free(cli, sizeof(struct client));
|
||||
debug_msg("INHASH: clientid [%s] exist?: [%d]", clientid, (int)check_id(clientid));
|
||||
}
|
||||
del_node(tan->node);
|
||||
|
||||
topic_node_t->it->reason_code = 0x00;
|
||||
debug_msg("find and delete this client.");
|
||||
}else{ // not find the topic
|
||||
topic_node_t->it->reason_code = 0x11;
|
||||
debug_msg("not find and response ack.");
|
||||
}
|
||||
|
||||
// free local varibale
|
||||
nng_free(topic_str, topic_node_t->it->topic_filter.len+1);
|
||||
nng_free(tan, sizeof(struct topic_and_node));
|
||||
|
||||
topic_node_t = topic_node_t->next;
|
||||
}
|
||||
|
||||
// check treeDB
|
||||
// print_db_tree(work->db);
|
||||
|
||||
debug_msg("End of unsub ctx handle.\n");
|
||||
return SUCCESS;
|
||||
}
|
||||
|
497
nng/CMakeLists.txt
Normal file
497
nng/CMakeLists.txt
Normal file
@ -0,0 +1,497 @@
|
||||
#
|
||||
# Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
|
||||
# Copyright (c) 2012 Martin Sustrik All rights reserved.
|
||||
# Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
|
||||
# Copyright (c) 2015-2016 Jack R. Dunaway. All rights reserved.
|
||||
# Copyright 2016 Franklin "Snaipe" Mathieu <franklinmathieu@gmail.com>
|
||||
# Copyright 2018 Capitar IT Group BV <info@capitar.com>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"),
|
||||
# to deal in the Software without restriction, including without limitation
|
||||
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
# and/or sell copies of the Software, and to permit persons to whom
|
||||
# the Software is furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
project(nng C)
|
||||
include(CheckFunctionExists)
|
||||
include(CheckSymbolExists)
|
||||
include(CheckStructHasMember)
|
||||
include(CheckLibraryExists)
|
||||
include(CheckCSourceCompiles)
|
||||
include(CheckCCompilerFlag)
|
||||
include(CMakeDependentOption)
|
||||
include(GNUInstallDirs)
|
||||
include(TestBigEndian)
|
||||
include(FindUnixCommands)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
|
||||
|
||||
if (POLICY CMP0042)
|
||||
# Newer cmake on MacOS should use @rpath
|
||||
cmake_policy(SET CMP0042 NEW)
|
||||
endif ()
|
||||
if (POLICY CMP0079)
|
||||
cmake_policy(SET CMP0079 NEW)
|
||||
endif ()
|
||||
|
||||
if (POLICY CMP0028)
|
||||
# Double colon targets are only alias or imports.
|
||||
cmake_policy(SET CMP0028 NEW)
|
||||
endif ()
|
||||
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" isSystemDir)
|
||||
if ("${isSystemDir}" STREQUAL "-1")
|
||||
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
|
||||
endif ("${isSystemDir}" STREQUAL "-1")
|
||||
|
||||
set(NNG_DESCRIPTION "High-Performance Scalability Protocols NextGen")
|
||||
set(ISSUE_REPORT_MSG "Please consider opening an issue at https://github.com/nanomsg/nng")
|
||||
|
||||
# Determine library versions.
|
||||
file(READ "include/nng/nng.h" nng_ver_h)
|
||||
string(REGEX MATCH "NNG_MAJOR_VERSION ([0-9]*)" _ ${nng_ver_h})
|
||||
set(NNG_MAJOR_VERSION ${CMAKE_MATCH_1})
|
||||
string(REGEX MATCH "NNG_MINOR_VERSION ([0-9]*)" _ ${nng_ver_h})
|
||||
set(NNG_MINOR_VERSION ${CMAKE_MATCH_1})
|
||||
string(REGEX MATCH "NNG_PATCH_VERSION ([0-9]*)" _ ${nng_ver_h})
|
||||
set(NNG_PATCH_VERSION ${CMAKE_MATCH_1})
|
||||
string(REGEX MATCH "NNG_RELEASE_SUFFIX \"([a-z0-9]*)\"" _ ${nng_ver_h})
|
||||
if (NOT ("${CMAKE_MATCH_1}" STREQUAL ""))
|
||||
set(NNG_PRERELEASE "-${CMAKE_MATCH_1}")
|
||||
endif ()
|
||||
|
||||
set(NNG_ABI_SOVERSION 1)
|
||||
set(NNG_ABI_VERSION "${NNG_MAJOR_VERSION}.${NNG_MINOR_VERSION}.${NNG_PATCH_VERSION}${NNG_PRERELEASE}")
|
||||
set(NNG_PACKAGE_VERSION "${NNG_ABI_VERSION}")
|
||||
message("Configuring for NNG version ${NNG_ABI_VERSION}")
|
||||
|
||||
# User-defined options.
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build shared library" ${BUILD_SHARED_LIBS})
|
||||
|
||||
if (CMAKE_CROSSCOMPILING)
|
||||
set(NNG_NATIVE_BUILD OFF)
|
||||
else ()
|
||||
set(NNG_NATIVE_BUILD ON)
|
||||
endif ()
|
||||
|
||||
# We only build command line tools and tests if we are not in a
|
||||
# cross-compile situation. Cross-compiling users who still want to
|
||||
# build these must enable them explicitly. Some of these switches
|
||||
# must be enabled rather early as we use their values later.
|
||||
#option(NNG_TESTS "Build and run tests" ${NNG_NATIVE_BUILD})
|
||||
#option(NNG_TOOLS "Build extra tools" ${NNG_NATIVE_BUILD})
|
||||
#option(NNG_ENABLE_NNGCAT "Enable building nngcat utility." ${NNG_TOOLS})
|
||||
option(NNG_ENABLE_COVERAGE "Enable coverage reporting." OFF)
|
||||
|
||||
|
||||
# Enable access to private APIs for our own use.
|
||||
add_definitions(-DNNG_PRIVATE)
|
||||
|
||||
# We can use rlimit to configure the stack size for systems
|
||||
# that have too small defaults. This is not used for Windows,
|
||||
# which can grow thread stacks sensibly. (Note that NNG can get
|
||||
# by with a smallish stack, but application callbacks might require
|
||||
# larger values if using aio completion callbacks. TLS libraries may
|
||||
# require larger stacks however.)
|
||||
if (NOT WIN32)
|
||||
option(NNG_SETSTACKSIZE "Use rlimit for thread stack size" OFF)
|
||||
if (NNG_SETSTACKSIZE)
|
||||
add_definitions(-DNNG_SETSTACKSIZE)
|
||||
endif ()
|
||||
mark_as_advanced(NNG_SETSTACKSIZE)
|
||||
endif ()
|
||||
|
||||
option(NNG_ENABLE_STATS "Enable statistics" ON)
|
||||
if (NNG_ENABLE_STATS)
|
||||
add_definitions(-DNNG_ENABLE_STATS)
|
||||
endif ()
|
||||
mark_as_advanced(NNG_ENABLE_STATS)
|
||||
|
||||
if (NNG_RESOLV_CONCURRENCY)
|
||||
add_definitions(-DNNG_RESOLV_CONCURRENCY=${NNG_RESOLV_CONCURRENCY})
|
||||
endif ()
|
||||
mark_as_advanced(NNG_RESOLV_CONCURRENCY)
|
||||
|
||||
if (NNG_NUM_TASKQ_THREADS)
|
||||
add_definitions(-DNNG_NUM_TASKQ_THREADS=${NNG_NUM_TASKQ_THREADS})
|
||||
endif ()
|
||||
mark_as_advanced(NNG_NUM_TASKQ_THREADS)
|
||||
|
||||
set(NNG_MAX_TASKQ_THREADS 16 CACHE STRING "Upper bound on taskq threads, 0 for no limit")
|
||||
mark_as_advanced(NNG_MAX_TASKQ_THREADS)
|
||||
if (NNG_MAX_TASKQ_THREADS)
|
||||
add_definitions(-DNNG_MAX_TASKQ_THREADS=${NNG_MAX_TASKQ_THREADS})
|
||||
endif ()
|
||||
|
||||
# Platform checks.
|
||||
|
||||
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
||||
set(NNG_WARN_FLAGS "-Wall -Wextra -fno-omit-frame-pointer")
|
||||
elseif (CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
set(NNG_WARN_FLAGS "-Wall -Wextra -fno-omit-frame-pointer")
|
||||
endif ()
|
||||
|
||||
include(CheckSanitizer)
|
||||
CheckSanitizer()
|
||||
if (NOT NNG_SANITIZER STREQUAL "none")
|
||||
set(NNG_SANITIZER_FLAGS "-fsanitize=${NNG_SANITIZER}")
|
||||
endif ()
|
||||
|
||||
if (NNG_ENABLE_COVERAGE)
|
||||
# NB: This only works for GCC and Clang 3.0 and newer. If your stuff
|
||||
# is older than that, you will need to find something newer. For
|
||||
# correct reporting, we always turn off all optimizations.
|
||||
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
||||
set(NNG_COVERAGE_C_FLAGS "-g -O0 --coverage")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS --coverage)
|
||||
elseif (CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
set(NNG_COVERAGE_C_FLAGS "-g -O0 --coverage")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS --coverage)
|
||||
else ()
|
||||
message(FATAL_ERROR "Unable to enable coverage for your compiler.")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${NNG_WARN_FLAGS} ${NNG_COVERAGE_C_FLAGS} ${NNG_SANITIZER_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${NNG_WARN_FLAGS} ${NNG_COVERAGE_C_FLAGS} ${NNG_SANITIZER_FLAGS}")
|
||||
|
||||
TEST_BIG_ENDIAN(NNG_BIG_ENDIAN)
|
||||
if (NNG_BIG_ENDIAN)
|
||||
add_definitions(-DNNG_BIG_ENDIAN)
|
||||
else ()
|
||||
add_definitions(-DNNG_LITTLE_ENDIAN)
|
||||
endif ()
|
||||
|
||||
# If the compiler is not on Windows, does it support hiding the
|
||||
# symbols by default? For shared libraries we would like to do this.
|
||||
if (NOT WIN32 AND NOT CYGWIN)
|
||||
check_c_compiler_flag(-fvisibility=hidden NNG_HIDDEN_VISIBILITY)
|
||||
if (NNG_HIDDEN_VISIBILITY)
|
||||
add_definitions(-DNNG_HIDDEN_VISIBILITY)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
add_definitions(-DNNG_PLATFORM_POSIX)
|
||||
add_definitions(-DNNG_PLATFORM_LINUX)
|
||||
add_definitions(-DNNG_USE_EVENTFD)
|
||||
# Windows subsystem for Linux -- smells like Linux, but it has
|
||||
# some differences (SO_REUSEADDR for one).
|
||||
if (CMAKE_SYSTEM_VERSION MATCHES "Microsoft")
|
||||
add_definitions(-DNNG_PLATFORM_WSL)
|
||||
endif ()
|
||||
set(NNG_PLATFORM_POSIX ON)
|
||||
|
||||
elseif (CMAKE_SYSTEM_NAME MATCHES "Android")
|
||||
add_definitions(-DNNG_PLATFORM_POSIX)
|
||||
add_definitions(-DNNG_PLATFORM_LINUX)
|
||||
add_definitions(-DNNG_PLATFORM_ANDROID)
|
||||
add_definitions(-DNNG_USE_EVENTFD)
|
||||
set(NNG_PLATFORM_POSIX ON)
|
||||
|
||||
elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||
add_definitions(-DNNG_PLATFORM_POSIX)
|
||||
add_definitions(-DNNG_PLATFORM_DARWIN)
|
||||
set(NNG_PLATFORM_POSIX ON)
|
||||
|
||||
elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
|
||||
add_definitions(-DNNG_PLATFORM_POSIX)
|
||||
add_definitions(-DNNG_PLATFORM_FREEBSD)
|
||||
set(NNG_PLATFORM_POSIX ON)
|
||||
|
||||
elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD")
|
||||
add_definitions(-DNNG_PLATFORM_POSIX)
|
||||
add_definitions(-DNNG_PLATFORM_NETBSD)
|
||||
set(NNG_PLATFORM_POSIX ON)
|
||||
|
||||
elseif (CMAKE_SYSTEM_NAME MATCHES "OpenBSD")
|
||||
add_definitions(-DNNG_PLATFORM_POSIX)
|
||||
add_definitions(-DNNG_PLATFORM_OPENBSD)
|
||||
set(NNG_PLATFORM_POSIX ON)
|
||||
|
||||
elseif (CMAKE_SYSTEM_NAME MATCHES "SunOS")
|
||||
add_definitions(-DNNG_PLATFORM_POSIX)
|
||||
add_definitions(-DNNG_PLATFORM_SUNOS)
|
||||
set(NNG_PLATFORM_POSIX ON)
|
||||
|
||||
elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||
add_definitions(-DNNG_PLATFORM_WINDOWS)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_definitions(-D_CRT_RAND_S)
|
||||
set(NNG_PLATFORM_WINDOWS ON)
|
||||
|
||||
# Target Windows Vista and later
|
||||
add_definitions(-D_WIN32_WINNT=0x0600)
|
||||
list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_WIN32_WINNT=0x0600)
|
||||
|
||||
elseif (CMAKE_SYSTEM_NAME MATCHES "QNX")
|
||||
add_definitions(-DNNG_PLATFORM_POSIX)
|
||||
add_definitions(-D__EXT_BSD)
|
||||
add_definitions(-D_QNX_SOURCE)
|
||||
add_definitions(-DNNG_PLATFORM_QNX)
|
||||
set(NNG_PLATFORM_POSIX ON)
|
||||
|
||||
else ()
|
||||
message(AUTHOR_WARNING "WARNING: This platform may not be supported: ${CMAKE_SYSTEM_NAME}")
|
||||
message(AUTHOR_WARNING "${ISSUE_REPORT_MSG}")
|
||||
# blithely hope for POSIX to work
|
||||
add_definitions(-DNNG_PLATFORM_POSIX)
|
||||
endif ()
|
||||
|
||||
macro(nng_check_func SYM DEF)
|
||||
check_function_exists(${SYM} ${DEF})
|
||||
if (${DEF})
|
||||
add_definitions(-D${DEF}=1)
|
||||
endif ()
|
||||
endmacro(nng_check_func)
|
||||
|
||||
macro(nng_check_sym SYM HDR DEF)
|
||||
check_symbol_exists(${SYM} ${HDR} ${DEF})
|
||||
if (${DEF})
|
||||
add_definitions(-D${DEF}=1)
|
||||
endif ()
|
||||
endmacro(nng_check_sym)
|
||||
|
||||
macro(nng_check_lib LIB SYM DEF)
|
||||
check_library_exists(${LIB} ${SYM} "" ${DEF})
|
||||
if (${DEF})
|
||||
add_definitions(-D${DEF}=1)
|
||||
list(APPEND NNG_LIBS ${LIB})
|
||||
endif ()
|
||||
endmacro(nng_check_lib)
|
||||
|
||||
macro(nng_check_struct_member STR MEM HDR DEF)
|
||||
check_struct_has_member("struct ${STR}" ${MEM} ${HDR} ${DEF})
|
||||
if (${DEF})
|
||||
add_definitions(-D${DEF}=1)
|
||||
endif ()
|
||||
endmacro(nng_check_struct_member)
|
||||
|
||||
if (WIN32)
|
||||
# Windows is a special snowflake.
|
||||
list(APPEND NNG_LIBS ws2_32 mswsock advapi32)
|
||||
nng_check_sym(InitializeConditionVariable windows.h NNG_HAVE_CONDVAR)
|
||||
nng_check_sym(snprintf stdio.h NNG_HAVE_SNPRINTF)
|
||||
if (NOT NNG_HAVE_CONDVAR OR NOT NNG_HAVE_SNPRINTF)
|
||||
message(FATAL_ERROR
|
||||
"Modern Windows API support is missing. "
|
||||
"Versions of Windows prior to Vista are not supported. "
|
||||
"Further, the 32-bit MinGW environment is not supported. "
|
||||
"Ensure you have at least Windows Vista or newer, and are "
|
||||
"using either Visual Studio 2013 or newer or MinGW-W64.")
|
||||
endif ()
|
||||
else ()
|
||||
# Unconditionally declare the following feature test macros. These are
|
||||
# needed for some platforms (glibc and SunOS/illumos) and are harmless
|
||||
# on the others.
|
||||
add_definitions(-D_GNU_SOURCE)
|
||||
add_definitions(-D_REENTRANT)
|
||||
add_definitions(-D_THREAD_SAFE)
|
||||
add_definitions(-D_POSIX_PTHREAD_SEMANTICS)
|
||||
list(APPEND NNG_PKGS Threads)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
nng_check_func(lockf NNG_HAVE_LOCKF)
|
||||
nng_check_func(flock NNG_HAVE_FLOCK)
|
||||
nng_check_func(getrandom NNG_HAVE_GETRANDOM)
|
||||
nng_check_func(arc4random_buf NNG_HAVE_ARC4RANDOM)
|
||||
|
||||
nng_check_lib(rt clock_gettime NNG_HAVE_CLOCK_GETTIME)
|
||||
nng_check_lib(pthread sem_wait NNG_HAVE_SEMAPHORE_PTHREAD)
|
||||
nng_check_lib(pthread pthread_atfork NNG_HAVE_PTHREAD_ATFORK_PTHREAD)
|
||||
nng_check_lib(nsl gethostbyname NNG_HAVE_LIBNSL)
|
||||
nng_check_lib(socket socket NNG_HAVE_LIBSOCKET)
|
||||
|
||||
# GCC needs libatomic on some architectures (e.g. ARM) because the
|
||||
# underlying architecture may lack the necessary atomic primitives.
|
||||
# One hopes that the libatomic implementation is superior to just using
|
||||
# a pthread mutex. The symbol chosen here was identified from GCC's
|
||||
# libatomic map file.
|
||||
#
|
||||
# Arguably when using clang, compiler-rt might be better.
|
||||
nng_check_lib(atomic __atomic_load_1 NNG_HAVE_LIBATOMIC)
|
||||
|
||||
nng_check_sym(AF_UNIX sys/socket.h NNG_HAVE_UNIX_SOCKETS)
|
||||
nng_check_sym(backtrace_symbols_fd execinfo.h NNG_HAVE_BACKTRACE)
|
||||
nng_check_struct_member(msghdr msg_control sys/socket.h NNG_HAVE_MSG_CONTROL)
|
||||
nng_check_sym(eventfd sys/eventfd.h NNG_HAVE_EVENTFD)
|
||||
nng_check_sym(kqueue sys/event.h NNG_HAVE_KQUEUE)
|
||||
nng_check_sym(port_create port.h NNG_HAVE_PORT_CREATE)
|
||||
nng_check_sym(epoll_create sys/epoll.h NNG_HAVE_EPOLL)
|
||||
nng_check_sym(epoll_create1 sys/epoll.h NNG_HAVE_EPOLL_CREATE1)
|
||||
nng_check_sym(getpeereid unistd.h NNG_HAVE_GETPEEREID)
|
||||
nng_check_sym(SO_PEERCRED sys/socket.h NNG_HAVE_SOPEERCRED)
|
||||
nng_check_struct_member(sockpeercred uid sys/socket.h NNG_HAVE_SOCKPEERCRED)
|
||||
nng_check_sym(LOCAL_PEERCRED sys/un.h NNG_HAVE_LOCALPEERCRED)
|
||||
nng_check_sym(getpeerucred ucred.h NNG_HAVE_GETPEERUCRED)
|
||||
nng_check_sym(atomic_flag_test_and_set stdatomic.h NNG_HAVE_STDATOMIC)
|
||||
|
||||
endif ()
|
||||
|
||||
nng_check_sym(strlcpy string.h NNG_HAVE_STRLCPY)
|
||||
nng_check_sym(strnlen string.h NNG_HAVE_STRNLEN)
|
||||
nng_check_sym(strcasecmp string.h NNG_HAVE_STRCASECMP)
|
||||
nng_check_sym(strncasecmp string.h NNG_HAVE_STRNCASECMP)
|
||||
|
||||
# Set a static symbol. We do this for testing, so that tests can
|
||||
# be skipped if they would rely on symbols that might not be exported.
|
||||
# For example, idhash depends on private symbols, so don't test it
|
||||
# when using a shared library on Windows because the symbols won't
|
||||
# resolve.
|
||||
if (NOT (BUILD_SHARED_LIBS))
|
||||
set(NNG_STATIC_LIB ON)
|
||||
message(STATUS "Building static libs")
|
||||
endif ()
|
||||
|
||||
# In order to facilitate testing, we want to add a library that includes
|
||||
# our common test code. We do this before iterating everywhere else so
|
||||
# that we can locate our tests inside the directories where we want.
|
||||
if (NNG_TESTS)
|
||||
enable_testing()
|
||||
set(all_tests, "")
|
||||
endif ()
|
||||
|
||||
macro(nng_test NAME)
|
||||
if (NNG_TESTS)
|
||||
add_executable(${NAME} ${NAME}.c ${ARGN})
|
||||
target_link_libraries(${NAME} ${PROJECT_NAME}_testlib)
|
||||
target_include_directories(${NAME} PRIVATE
|
||||
${PROJECT_SOURCE_DIR}/tests
|
||||
${PROJECT_SOURCE_DIR}/src
|
||||
${PROJECT_SOURCE_DIR}/include)
|
||||
add_test(NAME ${NAME} COMMAND ${NAME} -t)
|
||||
set_tests_properties(${NAME} PROPERTIES TIMEOUT 180)
|
||||
endif ()
|
||||
endmacro()
|
||||
|
||||
function(nng_sources_testlib)
|
||||
if (NNG_TESTS)
|
||||
foreach (f ${ARGN})
|
||||
target_sources(${PROJECT_NAME}_testlib PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/${f})
|
||||
endforeach ()
|
||||
endif ()
|
||||
endfunction()
|
||||
|
||||
function(nng_headers_testlib)
|
||||
if (NNG_TESTS)
|
||||
foreach (f ${ARGN})
|
||||
target_sources(${PROJECT_NAME}_testlib PRIVATE ${PROJECT_SOURCE_DIR}/include/${f})
|
||||
endforeach ()
|
||||
endif ()
|
||||
endfunction()
|
||||
|
||||
function(nng_defines_testlib)
|
||||
if (NNG_TESTS)
|
||||
target_compile_definitions(${PROJECT_NAME}_testlib PRIVATE ${ARGN})
|
||||
endif ()
|
||||
endfunction()
|
||||
|
||||
function(nng_sources)
|
||||
foreach (f ${ARGN})
|
||||
target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/${f})
|
||||
endforeach ()
|
||||
nng_sources_testlib(${ARGN})
|
||||
endfunction()
|
||||
|
||||
function(nng_headers)
|
||||
foreach (f ${ARGN})
|
||||
target_sources(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/include/${f})
|
||||
endforeach ()
|
||||
nng_headers_testlib(${ARGN})
|
||||
endfunction()
|
||||
|
||||
function(nng_defines)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE ${ARGN})
|
||||
nng_defines_testlib(${ARGN})
|
||||
endfunction()
|
||||
|
||||
# nng_sources_if adds the sources unconditionally to the test library,
|
||||
# but conditionally to the production library. This allows us to get
|
||||
# full test coverage while allowing a minimized delivery.
|
||||
function(nng_sources_if COND)
|
||||
if (${COND})
|
||||
foreach (f ${ARGN})
|
||||
target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/${f})
|
||||
endforeach ()
|
||||
endif ()
|
||||
nng_sources_testlib(${ARGN})
|
||||
endfunction()
|
||||
|
||||
function(nng_headers_if COND)
|
||||
if (COND)
|
||||
foreach (f ${ARGN})
|
||||
target_sources(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/include/${f})
|
||||
endforeach ()
|
||||
endif ()
|
||||
nng_headers_testlib(${ARGN})
|
||||
endfunction()
|
||||
|
||||
function(nng_defines_if COND)
|
||||
if (${COND})
|
||||
# Revisit this one
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC ${ARGN})
|
||||
endif ()
|
||||
nng_defines_testlib(${ARGN})
|
||||
endfunction()
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
foreach (_PKG IN ITEMS ${NNG_PKGS})
|
||||
find_package(${_PKG} REQUIRED)
|
||||
endforeach ()
|
||||
add_definitions(${NNG_DEFS})
|
||||
|
||||
if (NNG_TESTS)
|
||||
#add_subdirectory(tests)
|
||||
#add_subdirectory(perf)
|
||||
endif ()
|
||||
|
||||
# Build the tools
|
||||
|
||||
if (NNG_ENABLE_NNGCAT)
|
||||
#add_subdirectory(tools/nngcat)
|
||||
endif ()
|
||||
|
||||
option(NNG_ENABLE_TLS "Enable TLS protocol" OFF)
|
||||
if (NNG_ENABLE_TLS)
|
||||
add_definitions(-DNNG_SUPP_TLS)
|
||||
set(NNG_SUPP_TLS ON)
|
||||
endif ()
|
||||
|
||||
#add_subdirectory(docs/man)
|
||||
# for deleting node when client closed abnormally
|
||||
include_directories(${CMAKE_SOURCE_DIR}/nanolib/include)
|
||||
|
||||
set(CPACK_PACKAGE_NAME ${PROJECT_NAME})
|
||||
set(CPACK_PACKAGE_VERSION ${NNG_PACKAGE_VERSION})
|
||||
set(CPACK_PACKAGE_CONTACT "nanomsg@freelists.org")
|
||||
set(CPACK_PACKAGE_VENDOR "nanomsg.org")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "nanomsg next generation library")
|
||||
set(CPACK_SOURCE_GENERATOR "TBZ2;TGZ;ZIP")
|
||||
set(CPACK_SOURCE_IGNORE_FILES "/build/;/.git/;~$;${CPACK_SOURCE_IGNORE_FILES}")
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME
|
||||
"${PROJECT_NAME}-v${NNG_PACKAGE_VERSION}-src")
|
||||
set(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt)
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY "nng")
|
||||
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-v${NNG_PACKAGE_VERSION}")
|
||||
|
||||
add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source)
|
||||
include(CPack)
|
201
nng/LICENSE
Normal file
201
nng/LICENSE
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
22
nng/LICENSE.txt
Normal file
22
nng/LICENSE.txt
Normal file
@ -0,0 +1,22 @@
|
||||
The MIT License
|
||||
|
||||
Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
|
||||
Copyright 2018 Capitar IT Group BV <info@capitar.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom
|
||||
the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
66
nng/Makefile
Normal file
66
nng/Makefile
Normal file
@ -0,0 +1,66 @@
|
||||
|
||||
include config.mk
|
||||
export EMQ_DEBUG=
|
||||
|
||||
PKG_NAME:=NanoMQ
|
||||
PKG_VERSION:=0.1
|
||||
|
||||
#PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
|
||||
PKG_SOURCE_URL:=
|
||||
PKG_MD5SUM:=
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/NanoMQ
|
||||
SECTION:=utils
|
||||
CATEGORY:=Utilities
|
||||
TITLE:=blazing fast + ultra lighweight MQTT edge broker
|
||||
#URL:=
|
||||
DEPENDS:=+libnl-tiny +librt
|
||||
endef
|
||||
|
||||
define Package/NanoMQ/description
|
||||
package to communicate with a dashboard
|
||||
endef
|
||||
|
||||
define Package/NanoMQ/config
|
||||
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(CP) ./src/ $(PKG_BUILD_DIR)/src
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Package/nng/postinst
|
||||
#!/bin/sh
|
||||
|
||||
endef
|
||||
|
||||
TARGET_CFLAGS:= \
|
||||
-I$(STAGING_DIR)/usr/include/libnl-tiny \
|
||||
-I$(STAGING_DIR)/usr/include/ \
|
||||
$(TARGET_CFLAGS)
|
||||
|
||||
TARGET_LDFLAGS:= \
|
||||
-lnl-tiny \
|
||||
$(TARGET_LDFLAGS)
|
||||
|
||||
MAKE_FLAGS += \
|
||||
OFLAGS="$(TARGET_CFLAGS) $(TARGET_LDFLAGS)" \
|
||||
CC="$(TARGET_CC)" \
|
||||
STRIP="/bin/true"
|
||||
|
||||
define Build/Compile
|
||||
$(MAKE) -C $(PKG_BUILD_DIR)/src $(MAKE_FLAGS)
|
||||
endef
|
||||
|
||||
define Package/NanoMQ/install
|
||||
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,dashboard))
|
30
nng/cmake/CheckSanitizer.cmake
Normal file
30
nng/cmake/CheckSanitizer.cmake
Normal file
@ -0,0 +1,30 @@
|
||||
#
|
||||
# Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
|
||||
# Copyright 2017 Capitar IT Group BV <info@capitar.com>
|
||||
#
|
||||
# This software is supplied under the terms of the MIT License, a
|
||||
# copy of which should be located in the distribution where this
|
||||
# file was obtained (LICENSE.txt). A copy of the license may also be
|
||||
# found online at https://opensource.org/licenses/MIT.
|
||||
#
|
||||
|
||||
macro (CheckSanitizer)
|
||||
|
||||
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
||||
set(NNG_SAN_LIST none address leak memory thread undefined)
|
||||
elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||
set(NNG_SAN_LIST none address leak memory thread undefined)
|
||||
elseif (CMAKE_C_COMPILER_ID STREQUAL "AppleClang")
|
||||
set(NNG_SAN_LIST none address thread undefined)
|
||||
else ()
|
||||
set(NNG_SAN_LIST none)
|
||||
endif ()
|
||||
set (NNG_SANITIZER none CACHE STRING "Sanitizer to use (clang or gcc).")
|
||||
set_property(CACHE NNG_SANITIZER PROPERTY STRINGS ${NNG_SAN_LIST})
|
||||
mark_as_advanced (NNG_SANITIZER)
|
||||
|
||||
if (NOT NNG_SANITIZER STREQUAL "none")
|
||||
set (NNG_C_FLAG_SANITIZER "-fsanitize=${NNG_SANITIZER}")
|
||||
message(STATUS "Enabling sanitizer: ${NNG_C_FLAG_SANITIZER}")
|
||||
endif()
|
||||
endmacro ()
|
80
nng/cmake/FindmbedTLS.cmake
Normal file
80
nng/cmake/FindmbedTLS.cmake
Normal file
@ -0,0 +1,80 @@
|
||||
#
|
||||
# Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
|
||||
# Copyright 2017 Capitar IT Group BV <info@capitar.com>
|
||||
#
|
||||
# This software is supplied under the terms of the MIT License, a
|
||||
# copy of which should be located in the distribution where this
|
||||
# file was obtained (LICENSE.txt). A copy of the license may also be
|
||||
# found online at https://opensource.org/licenses/MIT.
|
||||
#
|
||||
|
||||
#
|
||||
# Try to find the Mbed TLS libraries.
|
||||
#
|
||||
# Sets the following:
|
||||
#
|
||||
# MBEDTLS_INCLUDE_DIR - Where to find mbedtls/ssl.h, etc.
|
||||
# MBEDTLS_FOUND - True if we found Mbed TLS.
|
||||
# MBEDTLS_CRYPTO_LIBRARY - The mbedcrypto library.
|
||||
# MBEDTLS_X509_LIBRARY - The mbedx509 library.
|
||||
# MBEDTLS_TLS_LIBRARY - The mbedtls library.
|
||||
# MBEDTLS_LIBRARIES - List of all three Mbed TLS libraries.
|
||||
# MBEDTLS_VERSION - $major.$minor.$revision (e.g. ``2.6.0``).
|
||||
#
|
||||
# Hints:
|
||||
#
|
||||
# Set ``MBEDTLS_ROOT_DIR`` to the root directory of Mbed TLS installation.
|
||||
#
|
||||
|
||||
set(_MBEDTLS_ROOT_HINTS ${MBEDTLS_ROOT_DIR} ENV MBEDTLS_ROOT_DIR)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_path(MBEDTLS_INCLUDE_DIR
|
||||
NAMES mbedtls/ssl.h
|
||||
HINTS ${_MBEDTLS_ROOT_HINTS}
|
||||
PATHS /usr/local
|
||||
PATH_SUFFIXES include)
|
||||
|
||||
find_library(MBEDTLS_CRYPTO_LIBRARY
|
||||
NAMES mbedcrypto
|
||||
HINTS ${_MBEDTLS_ROOT_HINTS}
|
||||
PATHS /usr/local
|
||||
PATH_SUFFIXES lib)
|
||||
|
||||
find_library(MBEDTLS_X509_LIBRARY
|
||||
NAMES mbedx509
|
||||
HINTS ${_MBEDTLS_ROOT_HINTS}
|
||||
PATHS /usr/local
|
||||
PATH_SUFFIXES lib)
|
||||
|
||||
find_library(MBEDTLS_TLS_LIBRARY
|
||||
NAMES mbedtls
|
||||
HINTS ${_MBEDTLS_ROOT_HINTS}
|
||||
PATHS /usr/local
|
||||
PATH_SUFFIXES lib)
|
||||
|
||||
set(MBEDTLS_LIBRARIES
|
||||
${MBEDTLS_TLS_LIBRARY}
|
||||
${MBEDTLS_X509_LIBRARY}
|
||||
${MBEDTLS_CRYPTO_LIBRARY})
|
||||
|
||||
if (${MBEDTLS_TLS_LIBRARY-NOTFOUND})
|
||||
message(FATAL_ERROR "Failed to find Mbed TLS library")
|
||||
endif()
|
||||
|
||||
mark_as_advanced(
|
||||
MBEDSSL_INCLUDE_DIR
|
||||
MBEDTLS_LIBRARIES
|
||||
MBEDTLS_CRYPTO_LIBRARY
|
||||
MBEDTLS_X509_LIBRARY
|
||||
MBEDTLS_TLS_LIBRARY)
|
||||
|
||||
# Extract the version from the header... hopefully it matches the library.
|
||||
file(STRINGS ${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h _MBEDTLS_VERLINE
|
||||
REGEX "^#define[ \t]+MBEDTLS_VERSION_STRING[\t ].*")
|
||||
string(REGEX REPLACE ".*MBEDTLS_VERSION_STRING[\t ]+\"(.*)\"" "\\1" MBEDTLS_VERSION ${_MBEDTLS_VERLINE})
|
||||
|
||||
find_package_handle_standard_args(mbedTLS
|
||||
REQUIRED_VARS MBEDTLS_TLS_LIBRARY MBEDTLS_CRYPTO_LIBRARY MBEDTLS_X509_LIBRARY MBEDTLS_INCLUDE_DIR VERSION_VAR MBEDTLS_VERSION)
|
||||
|
26
nng/cmake/nng-config.cmake.in
Normal file
26
nng/cmake/nng-config.cmake.in
Normal file
@ -0,0 +1,26 @@
|
||||
# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
|
||||
#
|
||||
# This software is supplied under the terms of the MIT License, a
|
||||
# copy of which should be located in the distribution where this
|
||||
# file was obtained (LICENSE.txt). A copy of the license may also be
|
||||
# found online at https://opensource.org/licenses/MIT.
|
||||
|
||||
|
||||
@PACKAGE_INIT@
|
||||
|
||||
set(NNG_VERSION_MAJOR "@NNG_VERSION_MAJOR@")
|
||||
set(NNG_VERSION_MINOR "@NNG_VERSION_MINOR@")
|
||||
set(NNG_VERSION_PATCH "@NNG_VERSION_PATCH@")
|
||||
|
||||
set_and_check(NNG_INCLUDE_DIRS "@PACKAGE_INCLUDE_INSTALL_DIRS@")
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/nng-targets.cmake")
|
||||
|
||||
# Make sure we find packages for our dependencies
|
||||
foreach(_PKG IN ITEMS @NNG_PKGS@)
|
||||
find_package(${_PKG} REQUIRED)
|
||||
endforeach ()
|
||||
|
||||
set(NNG_LIBRARY nng::nng)
|
||||
|
||||
check_required_components(@PROJECT_NAME@)
|
74
nng/etc/README.adoc
Normal file
74
nng/etc/README.adoc
Normal file
@ -0,0 +1,74 @@
|
||||
About This Directory
|
||||
====================
|
||||
|
||||
This directory contains support files that I use for developing this
|
||||
project. I recommend others consider doing the same.
|
||||
|
||||
|
||||
Coding Style
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A clang-format configuration file is included in the project, you should
|
||||
use that. (clang format requires that the style file live at the top of
|
||||
of the project tree, not somewhere else, such as this etc directory.) The
|
||||
format rules are probably inappropriate for the test/ subdirectory, as
|
||||
the Convey framework has a style all it's own.
|
||||
|
||||
The style is based loosely on WebKit, but is really modified -- someday
|
||||
if clang-format ever learns about BSD KNF I'll probably switch to that.
|
||||
|
||||
Once upon a time this used uncrustify. However, the frequent breaking changes
|
||||
in uncrustify versions, and the fact that the latest (at this time 0.65) does
|
||||
not actually support one of the most common language constructs (extern "C"
|
||||
opening braces) has driven me towards clang-format. The good news is that
|
||||
this is probably actually easier for most folks to use.
|
||||
|
||||
|
||||
Sublime Text
|
||||
~~~~~~~~~~~~
|
||||
|
||||
I've also arranged for Sublime text to understand that .h is C, not C++ (this
|
||||
is important!)
|
||||
|
||||
|
||||
ISO Standard C
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
I've decided, after some gnashing of teeth, to finally accept that C99
|
||||
is here to stay. Therefore, I'm *not* spending any effort into supporting
|
||||
older C89/C90 compilers. That said I do understand that compiler support
|
||||
for C99 is not always complete. I will stick to the mainstream features,
|
||||
like <stdint.h>, the ability to use variadic macros, // comments, and perhaps
|
||||
the occasional use of for() locally scoped variables.
|
||||
|
||||
We also insist that you have working vsnprintf, snprintf. Microsoft famously
|
||||
did not, or worse, had broken ones (that didn't guarantee NULL termination).
|
||||
Visual Studio 2015 reportedly fixes this. Building with older versions of
|
||||
Visual Studio for Microsoft platforms may leave you with some brittle code
|
||||
that could break in some bad ways -- use the latest to avoid this issue.
|
||||
(I'm not aware of any other platform with this kind of brain damage.)
|
||||
|
||||
Naming Conventions
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Because not everyone wants to deal with CMake all the time, I anticipate that
|
||||
there will be folks who in the future want to just create one monster .c
|
||||
file that contains all these things, or even a .h that they just inline into
|
||||
their programmer. As vile as this idea seems to me, I can understand the
|
||||
motivations for it. In order to facilitate those cases, its important that
|
||||
all global symbols use names prefixed with nni_ or nng_ (or NNI_ or NNG_ for
|
||||
macro names). This is true even for static symbols that won't show up in
|
||||
a more conventional symbol table.
|
||||
|
||||
We use nng_ (and NNG_) for symbols that are intended to be expoed to consumers.
|
||||
These symbols form part of our public API.
|
||||
|
||||
We use nni_ and NNI_ for symbols that are *NOT* part of our public API and
|
||||
should not be used by users.
|
||||
|
||||
Note that for the most part we try to avoid exposing structures directly to
|
||||
users so that they don't get baked into binaries -- preferring instead to
|
||||
dynamically allocate and give back an opaque pointer to the API. Any
|
||||
exceptions to this case need to be VERY carefully reviewed to make sure
|
||||
that the thing is unlikely to change (in any way whatsoever) in the future,
|
||||
or that adequate provisions for versioning have been made.
|
20
nng/etc/codecov.sh
Executable file
20
nng/etc/codecov.sh
Executable file
@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2017 Garrett D'Amore <garrett@damore.org>
|
||||
# Copyright 2017 Capitar IT Group BV <info@capitar.com>
|
||||
#
|
||||
# This software is supplied under the terms of the MIT License, a
|
||||
# copy of which should be located in the distribution where this
|
||||
# file was obtained (LICENSE.txt). A copy of the license may also be
|
||||
# found online at https://opensource.org/licenses/MIT.
|
||||
|
||||
if [ "${COVERAGE}" != ON ]
|
||||
then
|
||||
echo "Code coverage not enabled."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
GCOV=${GCOV:-gcov}
|
||||
|
||||
bash <(curl -s https://codecov.io/bash) -x gcov || echo "Codecov did not collect coverage"
|
||||
echo 0
|
33
nng/etc/coverage.sh
Executable file
33
nng/etc/coverage.sh
Executable file
@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2017 Garrett D'Amore <garrett@damore.org>
|
||||
# Copyright 2017 Capitar IT Group BV <info@capitar.com>
|
||||
#
|
||||
# This software is supplied under the terms of the MIT License, a
|
||||
# copy of which should be located in the distribution where this
|
||||
# file was obtained (LICENSE.txt). A copy of the license may also be
|
||||
# found online at https://opensource.org/licenses/MIT.
|
||||
|
||||
if [ "${COVERAGE}" != ON ]
|
||||
then
|
||||
echo "Code coverage not enabled."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
GCOV=${GCOV:-gcov}
|
||||
|
||||
# capture all coverage info
|
||||
lcov --gcov-tool ${GCOV} --directory . --capture --output-file coverage.info || exit 1
|
||||
|
||||
# filter out system information (C++ templates & inlines)
|
||||
lcov --remove coverage.info '/usr/*' --output-file coverage.info || exit 1
|
||||
|
||||
# filter out the *test* program data
|
||||
lcov --remove coverage.info '*/tests/*' --output-file coverage.info || exit 1
|
||||
|
||||
# emit debug stats.
|
||||
lcov --list coverage.info
|
||||
|
||||
rm coverage.info
|
||||
|
||||
echo 0
|
94
nng/etc/format-check.sh
Executable file
94
nng/etc/format-check.sh
Executable file
@ -0,0 +1,94 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright 2016 Garrett D'Amore <garrett@damore.org>
|
||||
#
|
||||
# This software is supplied under the terms of the MIT License, a
|
||||
# copy of which should be located in the distribution where this
|
||||
# file was obtained (LICENSE.txt). A copy of the license may also be
|
||||
# found online at https://opensource.org/licenses/MIT.
|
||||
#
|
||||
|
||||
#
|
||||
# This script is used to run uncrustify and report files that don't match.
|
||||
# It looks for .c and .h files, located in ../src, and uses the config file
|
||||
# uncrustify.cfg located in the same directory as this script. It only handles
|
||||
# C language at this point.
|
||||
#
|
||||
CLANG_FORMAT=${CLANG_FORMAT:-clang-format}
|
||||
case "${CLANG_FORMAT}" in
|
||||
no|off|skip|NO|OFF|SKIP)
|
||||
echo "format checks skipped"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
mydir=$(dirname $0)
|
||||
srcdir=${mydir}/../src
|
||||
failed=
|
||||
|
||||
vers=$(${CLANG_FORMAT} -version)
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "clang format not found? Skipping checks."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
versno=${vers#clang-format version }
|
||||
prefix=${vers%${versno}}
|
||||
|
||||
if [ "$prefix" != "clang-format version " ]
|
||||
then
|
||||
echo "clang-format version misparsed. Skipping checks."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# strip off any -ubuntu suffix
|
||||
versno=${versno%%-*}
|
||||
maj=${versno%%.*}
|
||||
rem=${versno#*.}
|
||||
min=${rem%%.*}
|
||||
|
||||
if [ "${maj}" -lt 3 ]; then
|
||||
echo "clang-format is too old. Skipping checks."
|
||||
exit 0
|
||||
fi
|
||||
if [ "${maj}" -eq 3 -a "${min}" -lt 6 ]; then
|
||||
echo "clang-format is too old. Skipping checks."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
mytmpdir=$(mktemp -d)
|
||||
|
||||
diffprog=${DIFF:-diff}
|
||||
if [ -t 1 ]; then
|
||||
if colordiff -q /dev/null > /dev/null 2>&1; then
|
||||
diffprog=${DIFF:-colordiff}
|
||||
fi
|
||||
fi
|
||||
|
||||
cd ${srcdir}
|
||||
for file in $(find . -name '*.[ch]' -print)
|
||||
do
|
||||
ext=${file##*.}
|
||||
oldf=${file}
|
||||
newf=${mytmpdir}/new.${ext}
|
||||
# If we do not understand the format file, then do nothing
|
||||
# Our style requires a relatively modern clang-format, which is
|
||||
# older than is found on some Linux distros.
|
||||
${CLANG_FORMAT} -fallback-style=none -style=file ${oldf} > ${newf}
|
||||
cmp -s ${oldf} ${newf}
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "${file} style changes"
|
||||
${diffprog} -u $oldf $newf
|
||||
failed=1
|
||||
fi
|
||||
done
|
||||
rm -rf $mytmpdir
|
||||
if [ -n "$failed" ]
|
||||
then
|
||||
echo "Format differences found!" 1>&2
|
||||
# Sadly, there are different versions of Uncrustify, and they don't
|
||||
# seem to universally agree. So let's not trigger a build error on
|
||||
# this -- but instead just emit it to standard output.
|
||||
exit 0
|
||||
fi
|
17
nng/etc/nng.sublime-project
Normal file
17
nng/etc/nng.sublime-project
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"folders":
|
||||
[
|
||||
{
|
||||
"path": ".."
|
||||
}
|
||||
],
|
||||
"settings":
|
||||
{
|
||||
"tab_size": 8,
|
||||
"translate_tabs_to_spaces": false,
|
||||
"ClangFormat": {
|
||||
"style": "File",
|
||||
"format_on_save": true
|
||||
}
|
||||
}
|
||||
}
|
33
nng/include/nng/compat/nanomsg/bus.h
Normal file
33
nng/include/nng/compat/nanomsg/bus.h
Normal file
@ -0,0 +1,33 @@
|
||||
//
|
||||
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
|
||||
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
|
||||
//
|
||||
// This software is supplied under the terms of the MIT License, a
|
||||
// copy of which should be located in the distribution where this
|
||||
// file was obtained (LICENSE.txt). A copy of the license may also be
|
||||
// found online at https://opensource.org/licenses/MIT.
|
||||
//
|
||||
|
||||
#ifndef NNG_COMPAT_BUS_H
|
||||
#define NNG_COMPAT_BUS_H
|
||||
|
||||
// This header contains interfaces that are intended to offer compatibility
|
||||
// with nanomsg v1.0. These are not the "preferred" interfaces for nng,
|
||||
// and consumers should only use these if they are porting software that
|
||||
// previously used nanomsg. New programs should use the nng native APIs.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// BUS sockopt level.
|
||||
#define NN_PROTO_BUS 7
|
||||
#define NN_BUS (NN_PROTO_BUS * 16 + 0)
|
||||
|
||||
// BUS has no options.
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NNG_COMPAT_BUS_H
|
31
nng/include/nng/compat/nanomsg/inproc.h
Normal file
31
nng/include/nng/compat/nanomsg/inproc.h
Normal file
@ -0,0 +1,31 @@
|
||||
//
|
||||
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
|
||||
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
|
||||
//
|
||||
// This software is supplied under the terms of the MIT License, a
|
||||
// copy of which should be located in the distribution where this
|
||||
// file was obtained (LICENSE.txt). A copy of the license may also be
|
||||
// found online at https://opensource.org/licenses/MIT.
|
||||
//
|
||||
|
||||
#ifndef NNG_COMPAT_INPROC_H
|
||||
#define NNG_COMPAT_INPROC_H
|
||||
|
||||
// This header contains interfaces that are intended to offer compatibility
|
||||
// with nanomsg v1.0. These are not the "preferred" interfaces for nng,
|
||||
// and consumers should only use these if they are porting software that
|
||||
// previously used nanomsg. New programs should use the nng native APIs.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// inproc sockopt level.
|
||||
// There are no inproc tunables.
|
||||
#define NN_INPROC (-1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NNG_COMPAT_INPROC_H
|
39
nng/include/nng/compat/nanomsg/ipc.h
Normal file
39
nng/include/nng/compat/nanomsg/ipc.h
Normal file
@ -0,0 +1,39 @@
|
||||
//
|
||||
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
|
||||
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
|
||||
//
|
||||
// This software is supplied under the terms of the MIT License, a
|
||||
// copy of which should be located in the distribution where this
|
||||
// file was obtained (LICENSE.txt). A copy of the license may also be
|
||||
// found online at https://opensource.org/licenses/MIT.
|
||||
//
|
||||
|
||||
#ifndef NNG_COMPAT_IPC_H
|
||||
#define NNG_COMPAT_IPC_H
|
||||
|
||||
// This header contains interfaces that are intended to offer compatibility
|
||||
// with nanomsg v1.0. These are not the "preferred" interfaces for nng,
|
||||
// and consumers should only use these if they are porting software that
|
||||
// previously used nanomsg. New programs should use the nng native APIs.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// IPC sockopt level.
|
||||
#define NN_IPC (-2)
|
||||
|
||||
// IPC options. Note that these are not currently supported.
|
||||
// IPC_SEC_ATTR works quite differently in NNG, and must be
|
||||
// configured using the new API. The buffer sizing options are
|
||||
// not supported at all. None of these were ever documented, and
|
||||
// are offered here only for source compatibility.
|
||||
#define NN_IPC_SEC_ATTR 1
|
||||
#define NN_IPC_OUTBUFSZ 2
|
||||
#define NN_IPC_INBUFSZ 3
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NNG_COMPAT_IPC_H
|
284
nng/include/nng/compat/nanomsg/nn.h
Normal file
284
nng/include/nng/compat/nanomsg/nn.h
Normal file
@ -0,0 +1,284 @@
|
||||
//
|
||||
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
|
||||
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
|
||||
//
|
||||
// This software is supplied under the terms of the MIT License, a
|
||||
// copy of which should be located in the distribution where this
|
||||
// file was obtained (LICENSE.txt). A copy of the license may also be
|
||||
// found online at https://opensource.org/licenses/MIT.
|
||||
//
|
||||
|
||||
#ifndef NNG_COMPAT_NN_H
|
||||
#define NNG_COMPAT_NN_H
|
||||
|
||||
// This header contains interfaces that are intended to offer compatibility
|
||||
// with nanomsg v1.0. These are not the "preferred" interfaces for nng,
|
||||
// and consumers should only use these if they are porting software that
|
||||
// previously used nanomsg. New programs should use the nng native APIs.
|
||||
|
||||
// Note that compatibility promises are limited to public portions of the
|
||||
// nanomsg API, and specifically do NOT extend to the ABI. Furthermore,
|
||||
// there may be other limitations around less commonly used portions of the
|
||||
// API; for example only SP headers may be transported in control data for
|
||||
// messages, there is almost no compatibility offered for statistics.
|
||||
// Error values may differ from those returned by nanomsg as well; the nng
|
||||
// error reporting facility expresses only a subset of the possibilities of
|
||||
// nanomsg.
|
||||
|
||||
// Note that unlike nanomsg, nng does not aggressively recycle socket or
|
||||
// endpoint IDs, which means applications which made assumptions that these
|
||||
// would be relatively small integers (e.g. to use them as array indices)
|
||||
// may break. (No promise about values was ever made.)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// clang-format gets in the way of most of this file.
|
||||
// We turn it off, at least until it gets smarter about aligning
|
||||
// macro definitions or we adopt enums or somesuch.
|
||||
// clang-format off
|
||||
|
||||
// NNG_DECL is used on declarations to deal with scope.
|
||||
// For building Windows DLLs, it should be the appropriate __declspec().
|
||||
// For shared libraries with platforms that support hidden visibility,
|
||||
// it should evaluate to __attribute__((visibility("default"))).
|
||||
#ifndef NN_DECL
|
||||
#if defined(_WIN32) && !defined(NNG_STATIC_LIB)
|
||||
#if defined(NNG_SHARED_LIB)
|
||||
#define NN_DECL __declspec(dllexport)
|
||||
#else
|
||||
#define NN_DECL __declspec(dllimport)
|
||||
#endif // NNG_SHARED_LIB
|
||||
#else
|
||||
#if defined(NNG_SHARED_LIB) && defined(NNG_HIDDEN_VISIBILITY)
|
||||
#define NN_DECL __attribute__((visibility("default")))
|
||||
#else
|
||||
#define NN_DECL extern
|
||||
#endif
|
||||
#endif // _WIN32 && !NNG_STATIC_LIB
|
||||
#endif // NN_DECL
|
||||
|
||||
#define AF_SP 1
|
||||
#define AF_SP_RAW 2
|
||||
|
||||
#define NN_SOCKADDR_MAX 128
|
||||
#define NN_SOL_SOCKET 0
|
||||
|
||||
// Flag for send/recv (nonblocking)
|
||||
#define NN_DONTWAIT 1
|
||||
|
||||
// CMSG data type
|
||||
#define PROTO_SP 1
|
||||
#define SP_HDR 1
|
||||
|
||||
// Errnos. Legacy nanomsg uses posix errnos where possible.
|
||||
// If a define is not set, use add NN_ERRBASE. nng does not
|
||||
// return all of these values, so there may be some loss of
|
||||
// of information for edge cases, but we don't expect that to be
|
||||
// a problem really.
|
||||
#define NN_ERRBASE (0x10000000)
|
||||
#ifndef ENOTSUP
|
||||
#define ENOTSUP (NN_ERRBASE+1)
|
||||
#endif
|
||||
#ifndef EPROTONOSUPPORT
|
||||
#define EPROTONOSUPPORT (NN_ERRBASE+2)
|
||||
#endif
|
||||
#ifndef ENOBUFS
|
||||
#define ENOBUFS (NN_ERRBASE+3)
|
||||
#endif
|
||||
#ifndef ENETDOWN
|
||||
#define ENETDOWN (NN_ERRBASE+4)
|
||||
#endif
|
||||
#ifndef EADDRINUSE
|
||||
#define EADDRINUSE (NN_ERRBASE+5)
|
||||
#endif
|
||||
#ifndef EADDRNOTAVAIL
|
||||
#define EADDRNOTAVAIL (NN_ERRBASE+6)
|
||||
#endif
|
||||
#ifndef ENOTSOCK
|
||||
#define ENOTSOCK (NN_ERRBASE+7)
|
||||
#endif
|
||||
#ifndef EAGAIN
|
||||
#define EAGAIN (NN_ERRBASE+8)
|
||||
#endif
|
||||
#ifndef EBADF
|
||||
#define EBADF (NN_ERRBASE+9)
|
||||
#endif
|
||||
#ifndef EINVAL
|
||||
#define EINVAL (NN_ERRBASE+10)
|
||||
#endif
|
||||
#ifndef EMFILE
|
||||
#define EMFILE (NN_ERRBASE+11)
|
||||
#endif
|
||||
#ifndef EFAULT
|
||||
#define EFAULT (NN_ERRBASE+12)
|
||||
#endif
|
||||
#ifndef EACCES
|
||||
#define EACCES (NN_ERRBASE+13)
|
||||
#endif
|
||||
#ifndef ENETRESET
|
||||
#define ENETRESET (NN_ERRBASE+14)
|
||||
#endif
|
||||
#ifndef ENETUNREACH
|
||||
#define ENETUNREACH (NN_ERRBASE+15)
|
||||
#endif
|
||||
#ifndef EHOSTUNREACH
|
||||
#define EHOSTUNREACH (NN_ERRBASE+16)
|
||||
#endif
|
||||
#ifndef EAFNOSUPPORT
|
||||
#define EAFNOSUPPORT (NN_ERRBASE+17)
|
||||
#endif
|
||||
#ifndef EINPROGRESS
|
||||
#define EINPROGRESS (NN_ERRBASE+18)
|
||||
#endif
|
||||
#ifndef EPROTO
|
||||
#define EPROTO (NN_ERRBASE+19)
|
||||
#endif
|
||||
#ifndef ECONNREFUSED
|
||||
#define ECONNREFUSED (NN_ERRBASE+20)
|
||||
#endif
|
||||
#ifndef ENOTCONN
|
||||
#define ENOTCONN (NN_ERRBASE+21)
|
||||
#endif
|
||||
#ifndef EMSGSIZE
|
||||
#define EMSGSIZE (NN_ERRBASE+22)
|
||||
#endif
|
||||
#ifndef ETIMEDOUT
|
||||
#define ETIMEDOUT (NN_ERRBASE+23)
|
||||
#endif
|
||||
#ifndef ECONNABORTED
|
||||
#define ECONNABORTED (NN_ERRBASE+24)
|
||||
#endif
|
||||
#ifndef ECONNRESET
|
||||
#define ECONNRESET (NN_ERRBASE+25)
|
||||
#endif
|
||||
#ifndef ENOPROTOOPT
|
||||
#define ENOPROTOOPT (NN_ERRBASE+26)
|
||||
#endif
|
||||
#ifndef EISCONN
|
||||
#define EISCONN (NN_ERRBASE+27)
|
||||
#endif
|
||||
#ifndef ESOCKNOSUPPORT
|
||||
#define ESOCKNOSPPORT (NN_ERRBASE+28)
|
||||
#endif
|
||||
#ifndef ETERM
|
||||
#define ETERM (NN_ERRBASE+29)
|
||||
#endif
|
||||
#ifndef EFSM
|
||||
#define EFSM (NN_ERRBASE+30)
|
||||
#endif
|
||||
#ifndef ENOENT
|
||||
#define ENOENT (NN_ERRBASE+31)
|
||||
#endif
|
||||
#ifndef EIO
|
||||
#define EIO (NN_ERRBASE+32)
|
||||
#endif
|
||||
#ifndef EEXIST
|
||||
#define EEXIST (NN_ERRBASE+33)
|
||||
#endif
|
||||
#ifndef ENOSPC
|
||||
#define ENOSPC (NN_ERRBASE+34)
|
||||
#endif
|
||||
|
||||
|
||||
// Socket options
|
||||
#define NN_LINGER 1
|
||||
#define NN_SNDBUF 2
|
||||
#define NN_RCVBUF 3
|
||||
#define NN_SNDTIMEO 4
|
||||
#define NN_RCVTIMEO 5
|
||||
#define NN_RECONNECT_IVL 6
|
||||
#define NN_RECONNECT_IVL_MAX 7
|
||||
#define NN_SNDPRIO 8
|
||||
#define NN_RCVPRIO 9
|
||||
#define NN_SNDFD 10
|
||||
#define NN_RCVFD 11
|
||||
#define NN_DOMAIN 12
|
||||
#define NN_PROTOCOL 13
|
||||
#define NN_IPV4ONLY 14
|
||||
#define NN_SOCKET_NAME 15
|
||||
#define NN_RCVMAXSIZE 16
|
||||
#define NN_MAXTTL 17
|
||||
|
||||
// from this point on formatting is fine
|
||||
// clang-format on
|
||||
|
||||
// Poll stuff
|
||||
#define NN_POLLIN 1
|
||||
#define NN_POLLOUT 2
|
||||
struct nn_pollfd {
|
||||
int fd;
|
||||
uint16_t events;
|
||||
uint16_t revents;
|
||||
};
|
||||
|
||||
// Magical size for allocation
|
||||
#define NN_MSG ((size_t) -1)
|
||||
|
||||
struct nn_iovec {
|
||||
void * iov_base;
|
||||
size_t iov_len;
|
||||
};
|
||||
|
||||
struct nn_msghdr {
|
||||
struct nn_iovec *msg_iov;
|
||||
int msg_iovlen;
|
||||
void * msg_control;
|
||||
size_t msg_controllen;
|
||||
};
|
||||
|
||||
struct nn_cmsghdr {
|
||||
size_t cmsg_len;
|
||||
int cmsg_level;
|
||||
int cmsg_type;
|
||||
};
|
||||
|
||||
#define NN_CMSG_ALIGN(len) \
|
||||
(((len) + sizeof(size_t) - 1) & (size_t) ~(sizeof(size_t) - 1))
|
||||
|
||||
// Unlike old nanomsg, we explicitly only support the SP header as attached
|
||||
// cmsg data. It turns out that old nanomsg didn't really store anything
|
||||
// useful otherwise anyway. (One specific exception was that it stored the
|
||||
// message type of text or binary for the websocket transport. We don't think
|
||||
// anyone used that in practice though.)
|
||||
#define NN_CMSG_FIRSTHDR(mh) nn_cmsg_next((struct nn_msghdr *) (mh), NULL)
|
||||
#define NN_CMSG_NXTHDR(mh, ch) \
|
||||
nn_cmsg_next((struct nn_msghdr *) (mh), (struct nn_cmsghdr *) ch)
|
||||
#define NN_CMSG_DATA(ch) ((unsigned char *) (((struct nn_cmsghdr *) (ch)) + 1))
|
||||
#define NN_CMSG_SPACE(len) \
|
||||
(NN_CMSG_ALIGN(len) + NN_CMSG_ALIGN(sizeof(struct nn_cmsghdr)))
|
||||
#define NN_CMSG_LEN(len) (NN_CMSG_ALIGN(sizeof(struct nn_cmsghdr)) + (len))
|
||||
|
||||
NN_DECL struct nn_cmsghdr *nn_cmsg_next(
|
||||
struct nn_msghdr *, struct nn_cmsghdr *);
|
||||
NN_DECL int nn_socket(int, int);
|
||||
NN_DECL int nn_setsockopt(int, int, int, const void *, size_t);
|
||||
NN_DECL int nn_getsockopt(int, int, int, void *, size_t *);
|
||||
NN_DECL int nn_bind(int, const char *);
|
||||
NN_DECL int nn_connect(int, const char *);
|
||||
NN_DECL int nn_shutdown(int, int);
|
||||
NN_DECL int nn_send(int, const void *, size_t, int);
|
||||
NN_DECL int nn_recv(int, void *, size_t, int);
|
||||
NN_DECL int nn_sendmsg(int, const struct nn_msghdr *, int);
|
||||
NN_DECL int nn_recvmsg(int, struct nn_msghdr *, int);
|
||||
NN_DECL int nn_close(int);
|
||||
NN_DECL int nn_poll(struct nn_pollfd *, int, int);
|
||||
NN_DECL int nn_device(int, int);
|
||||
NN_DECL uint64_t nn_get_statistic(int, int);
|
||||
NN_DECL void * nn_allocmsg(size_t, int);
|
||||
NN_DECL void * nn_reallocmsg(void *, size_t);
|
||||
NN_DECL int nn_freemsg(void *);
|
||||
NN_DECL int nn_errno(void);
|
||||
NN_DECL const char *nn_strerror(int);
|
||||
NN_DECL void nn_term(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NNG_COMPAT_NN_H
|
39
nng/include/nng/compat/nanomsg/pair.h
Normal file
39
nng/include/nng/compat/nanomsg/pair.h
Normal file
@ -0,0 +1,39 @@
|
||||
//
|
||||
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
|
||||
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
|
||||
//
|
||||
// This software is supplied under the terms of the MIT License, a
|
||||
// copy of which should be located in the distribution where this
|
||||
// file was obtained (LICENSE.txt). A copy of the license may also be
|
||||
// found online at https://opensource.org/licenses/MIT.
|
||||
//
|
||||
|
||||
#ifndef NNG_COMPAT_PAIR_H
|
||||
#define NNG_COMPAT_PAIR_H
|
||||
|
||||
// This header contains interfaces that are intended to offer compatibility
|
||||
// with nanomsg v1.0. These are not the "preferred" interfaces for nng,
|
||||
// and consumers should only use these if they are porting software that
|
||||
// previously used nanomsg. New programs should use the nng native APIs.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// PAIR sockopt level.
|
||||
#define NN_PROTO_PAIR 1
|
||||
#define NN_PAIR (NN_PROTO_PAIR * 16 + 0)
|
||||
|
||||
// These are technically "new", and not available in nanomsg, but
|
||||
// offered here as a transition aid. If you want to use the advanced
|
||||
// PAIRv1 options (POLYAMOROUS mode) you still need to use the new API.
|
||||
#define NN_PAIR_v0 (NN_PROTO_PAIR * 16 + 0)
|
||||
#define NN_PAIR_V1 (NN_PROTO_PAIR * 16 + 1)
|
||||
|
||||
// PAIR has no options.
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NNG_COMPAT_PAIR_H
|
34
nng/include/nng/compat/nanomsg/pipeline.h
Normal file
34
nng/include/nng/compat/nanomsg/pipeline.h
Normal file
@ -0,0 +1,34 @@
|
||||
//
|
||||
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
|
||||
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
|
||||
//
|
||||
// This software is supplied under the terms of the MIT License, a
|
||||
// copy of which should be located in the distribution where this
|
||||
// file was obtained (LICENSE.txt). A copy of the license may also be
|
||||
// found online at https://opensource.org/licenses/MIT.
|
||||
//
|
||||
|
||||
#ifndef NNG_COMPAT_PIPELINE_H
|
||||
#define NNG_COMPAT_PIPELINE_H
|
||||
|
||||
// This header contains interfaces that are intended to offer compatibility
|
||||
// with nanomsg v1.0. These are not the "preferred" interfaces for nng,
|
||||
// and consumers should only use these if they are porting software that
|
||||
// previously used nanomsg. New programs should use the nng native APIs.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// PUSH and PULL sockopt level.
|
||||
#define NN_PROTO_PIPELINE 5
|
||||
#define NN_PUSH (NN_PROTO_PIPELINE * 16 + 0)
|
||||
#define NN_PULL (NN_PROTO_PIPELINE * 16 + 1)
|
||||
|
||||
// PUSH and PULL have no options.
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NNG_COMPAT_PIPELINE_H
|
36
nng/include/nng/compat/nanomsg/pubsub.h
Normal file
36
nng/include/nng/compat/nanomsg/pubsub.h
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
|
||||
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
|
||||
//
|
||||
// This software is supplied under the terms of the MIT License, a
|
||||
// copy of which should be located in the distribution where this
|
||||
// file was obtained (LICENSE.txt). A copy of the license may also be
|
||||
// found online at https://opensource.org/licenses/MIT.
|
||||
//
|
||||
|
||||
#ifndef NNG_COMPAT_PUBSUB_H
|
||||
#define NNG_COMPAT_PUBSUB_H
|
||||
|
||||
// This header contains interfaces that are intended to offer compatibility
|
||||
// with nanomsg v1.0. These are not the "preferred" interfaces for nng,
|
||||
// and consumers should only use these if they are porting software that
|
||||
// previously used nanomsg. New programs should use the nng native APIs.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// PUB and SUB sockopt level.
|
||||
#define NN_PROTO_PUBSUB 2
|
||||
#define NN_PUB (NN_PROTO_PUBSUB * 16 + 0)
|
||||
#define NN_SUB (NN_PROTO_PUBSUB * 16 + 1)
|
||||
|
||||
// SUB options. (PUB has none.)
|
||||
#define NN_SUB_SUBSCRIBE (NN_SUB * 16 + 1)
|
||||
#define NN_SUB_UNSUBSCRIBE (NN_SUB * 16 + 2)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NNG_COMPAT_PUBSUB_H
|
35
nng/include/nng/compat/nanomsg/reqrep.h
Normal file
35
nng/include/nng/compat/nanomsg/reqrep.h
Normal file
@ -0,0 +1,35 @@
|
||||
//
|
||||
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
|
||||
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
|
||||
//
|
||||
// This software is supplied under the terms of the MIT License, a
|
||||
// copy of which should be located in the distribution where this
|
||||
// file was obtained (LICENSE.txt). A copy of the license may also be
|
||||
// found online at https://opensource.org/licenses/MIT.
|
||||
//
|
||||
|
||||
#ifndef NNG_COMPAT_REQREP_H
|
||||
#define NNG_COMPAT_REQREP_H
|
||||
|
||||
// This header contains interfaces that are intended to offer compatibility
|
||||
// with nanomsg v1.0. These are not the "preferred" interfaces for nng,
|
||||
// and consumers should only use these if they are porting software that
|
||||
// previously used nanomsg. New programs should use the nng native APIs.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// REQ and REP sockopt level.
|
||||
#define NN_PROTO_REQREP 3
|
||||
#define NN_REQ (NN_PROTO_REQREP * 16 + 0)
|
||||
#define NN_REP (NN_PROTO_REQREP * 16 + 1)
|
||||
|
||||
// REQ options. (REP has none.)
|
||||
#define NN_REQ_RESEND_IVL (NN_REQ * 16 + 1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NNG_COMPAT_REQREP_H
|
36
nng/include/nng/compat/nanomsg/survey.h
Normal file
36
nng/include/nng/compat/nanomsg/survey.h
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
|
||||
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
|
||||
//
|
||||
// This software is supplied under the terms of the MIT License, a
|
||||
// copy of which should be located in the distribution where this
|
||||
// file was obtained (LICENSE.txt). A copy of the license may also be
|
||||
// found online at https://opensource.org/licenses/MIT.
|
||||
//
|
||||
|
||||
#ifndef NNG_COMPAT_SURVEY_H
|
||||
#define NNG_COMPAT_SURVEY_H
|
||||
|
||||
// This header contains interfaces that are intended to offer compatibility
|
||||
// with nanomsg v1.0. These are not the "preferred" interfaces for nng,
|
||||
// and consumers should only use these if they are porting software that
|
||||
// previously used nanomsg. New programs should use the nng native APIs.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// SURVEYOR and RESPONDENT sockopt level.
|
||||
#define NN_PROTO_SURVEY 6
|
||||
#define NN_SURVEYOR (NN_PROTO_SURVEY * 16 + 2)
|
||||
#define NN_RESPONDENT (NN_PROTO_SURVEY * 16 + 3)
|
||||
|
||||
// SURVEYOR options. (RESPONDENT has none.)
|
||||
|
||||
#define NN_SURVEYOR_DEADLINE (NN_SURVEYOR * 16 + 1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NNG_COMPAT_SURVEY_H
|
33
nng/include/nng/compat/nanomsg/tcp.h
Normal file
33
nng/include/nng/compat/nanomsg/tcp.h
Normal file
@ -0,0 +1,33 @@
|
||||
//
|
||||
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
|
||||
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
|
||||
//
|
||||
// This software is supplied under the terms of the MIT License, a
|
||||
// copy of which should be located in the distribution where this
|
||||
// file was obtained (LICENSE.txt). A copy of the license may also be
|
||||
// found online at https://opensource.org/licenses/MIT.
|
||||
//
|
||||
|
||||
#ifndef NNG_COMPAT_TCP_H
|
||||
#define NNG_COMPAT_TCP_H
|
||||
|
||||
// This header contains interfaces that are intended to offer compatibility
|
||||
// with nanomsg v1.0. These are not the "preferred" interfaces for nng,
|
||||
// and consumers should only use these if they are porting software that
|
||||
// previously used nanomsg. New programs should use the nng native APIs.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// TCP sockopt level.
|
||||
#define NN_TCP (-3)
|
||||
|
||||
// TCP options.
|
||||
#define NN_TCP_NODELAY 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NNG_COMPAT_TCP_H
|
41
nng/include/nng/compat/nanomsg/ws.h
Normal file
41
nng/include/nng/compat/nanomsg/ws.h
Normal file
@ -0,0 +1,41 @@
|
||||
//
|
||||
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
|
||||
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
|
||||
//
|
||||
// This software is supplied under the terms of the MIT License, a
|
||||
// copy of which should be located in the distribution where this
|
||||
// file was obtained (LICENSE.txt). A copy of the license may also be
|
||||
// found online at https://opensource.org/licenses/MIT.
|
||||
//
|
||||
|
||||
#ifndef NNG_COMPAT_WS_H
|
||||
#define NNG_COMPAT_WS_H
|
||||
|
||||
// This header contains interfaces that are intended to offer compatibility
|
||||
// with nanomsg v1.0. These are not the "preferred" interfaces for nng,
|
||||
// and consumers should only use these if they are porting software that
|
||||
// previously used nanomsg. New programs should use the nng native APIs.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// WS sockopt level.
|
||||
#define NN_WS (-4)
|
||||
|
||||
// WS options.
|
||||
|
||||
// Note that while legacy libnanomsg had *some* support for text messages,
|
||||
// NNG only supports binary. Binary types are required to pass protocol
|
||||
// headers with NNG and nanomsg in any event. This means that the NNG
|
||||
// WebSocket support will not be compatible with some very old browsers.
|
||||
#define NN_WS_MSG_TYPE 1
|
||||