mirror of
https://dev.iopsys.eu/feed/iopsys.git
synced 2025-12-10 07:44:50 +01:00
move xmppc & stunc code to their individual repos
This commit is contained in:
parent
b30434d872
commit
88892e5f7c
29 changed files with 26 additions and 3352 deletions
|
|
@ -1,16 +0,0 @@
|
|||
PROG = stund
|
||||
OBJS = stun.o config.o log.o ubus.o
|
||||
|
||||
PROG_CFLAGS = $(CFLAGS) -Wall -Werror
|
||||
PROG_LDFLAGS = $(LDFLAGS) -lubus -luci -lubox -ljson-c -lcrypto -lblobmsg_json
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(PROG_CFLAGS) $(FPIC) -c -o $@ $<
|
||||
|
||||
all: $(PROG)
|
||||
|
||||
$(PROG): $(OBJS)
|
||||
$(CC) $(PROG_CFLAGS) -o $@ $^ $(PROG_LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -f *.o $(PROG)
|
||||
|
|
@ -1,297 +0,0 @@
|
|||
/*
|
||||
* config.c -- contains functions that allows reading and loading of uci config parameters of stun
|
||||
*
|
||||
* Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
|
||||
*
|
||||
* Author: Omar Kallel <omar.kallel@pivasoftware.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static struct uci_context *uci_ctx = NULL;
|
||||
static struct uci_context *uci_ctx_state = NULL;
|
||||
struct stun_config conf;
|
||||
|
||||
int config_fini(void)
|
||||
{
|
||||
free(conf.server_address);
|
||||
free(conf.password);
|
||||
free(conf.username);
|
||||
conf.server_address = NULL;
|
||||
conf.username = NULL;
|
||||
conf.password = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_init(void)
|
||||
{
|
||||
char *v;
|
||||
suci_init();
|
||||
memset(&conf, 0, sizeof(struct stun_config));
|
||||
|
||||
v = suci_get_value("stun", "stun", "server_address");
|
||||
if (!*v) {
|
||||
stun_log(SCRIT, "Missing Server Address in the STUN config");
|
||||
goto error;
|
||||
}
|
||||
conf.server_address = strdup(v);
|
||||
|
||||
v = suci_get_value("stun", "stun", "username");
|
||||
if (*v)
|
||||
conf.username = strdup(v);
|
||||
|
||||
v = suci_get_value("stun", "stun", "password");
|
||||
if (*v)
|
||||
conf.password = strdup(v);
|
||||
|
||||
v = suci_get_value("stun", "stun", "server_port");
|
||||
if (*v)
|
||||
conf.server_port = atoi(v);
|
||||
else
|
||||
conf.server_port = DEFAULT_SERVERPORT;
|
||||
|
||||
v = suci_get_value("stun", "stun", "log_level");
|
||||
if (*v)
|
||||
conf.loglevel = atoi(v);
|
||||
else
|
||||
conf.loglevel = DEFAULT_LOGLEVEL;
|
||||
|
||||
v = suci_get_value("stun", "stun", "min_keepalive");
|
||||
if (*v)
|
||||
conf.min_keepalive = atoi(v);
|
||||
else
|
||||
conf.min_keepalive = DEFAULT_MINKEEPALIVE;
|
||||
|
||||
v = suci_get_value("stun", "stun", "max_keepalive");
|
||||
if (*v)
|
||||
conf.max_keepalive = atoi(v);
|
||||
else
|
||||
conf.max_keepalive = DEFAULT_MAXKEEPALIVE;
|
||||
|
||||
v = suci_get_value("stun", "stun", "client_port");
|
||||
if (*v)
|
||||
conf.client_port = atoi(v);
|
||||
|
||||
if (conf.max_keepalive <= 0)
|
||||
conf.max_keepalive = DEFAULT_MAXKEEPALIVE;
|
||||
|
||||
if (conf.min_keepalive <= 0)
|
||||
conf.min_keepalive = DEFAULT_MINKEEPALIVE;
|
||||
|
||||
if (conf.server_port <= 0)
|
||||
conf.server_port = DEFAULT_SERVERPORT;
|
||||
|
||||
if (conf.loglevel >= __MAX_SLOG || conf.loglevel < 0) {
|
||||
conf.loglevel = DEFAULT_LOGLEVEL;
|
||||
}
|
||||
|
||||
stun_log(SINFO, "STUN CONFIG - Server Address: %s", conf.server_address);
|
||||
stun_log(SINFO, "STUN CONFIG - Username: %s", conf.username ? conf.username : "<not defined>");
|
||||
stun_log(SINFO, "STUN CONFIG - Server port: %d", conf.server_port);
|
||||
stun_log(SINFO, "STUN CONFIG - min keepalive: %d", conf.min_keepalive);
|
||||
stun_log(SINFO, "STUN CONFIG - max keepalive: %d", conf.max_keepalive);
|
||||
stun_log(SINFO, "STUN CONFIG - Client port: %d", (conf.client_port > 0) ? conf.client_port : -1);
|
||||
stun_log(SINFO, "STUN CONFIG - LOG Level: %d (Critical=0, Warning=1, Notice=2, Info=3, Debug=4)", conf.loglevel);
|
||||
suci_fini();
|
||||
return 0;
|
||||
|
||||
error:
|
||||
suci_fini();
|
||||
config_fini();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int suci_init(void)
|
||||
{
|
||||
uci_ctx = uci_alloc_context();
|
||||
if (!uci_ctx) {
|
||||
return -1;
|
||||
}
|
||||
uci_ctx_state = uci_alloc_context();
|
||||
if (!uci_ctx_state) {
|
||||
return -1;
|
||||
}
|
||||
uci_add_delta_path(uci_ctx_state, uci_ctx_state->savedir);
|
||||
uci_set_savedir(uci_ctx_state, VAR_STATE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int suci_fini(void)
|
||||
{
|
||||
if (uci_ctx) {
|
||||
uci_free_context(uci_ctx);
|
||||
}
|
||||
if (uci_ctx_state) {
|
||||
uci_free_context(uci_ctx_state);
|
||||
}
|
||||
uci_ctx = NULL;
|
||||
uci_ctx_state = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool suci_validate_section(const char *str)
|
||||
{
|
||||
if (!*str)
|
||||
return false;
|
||||
|
||||
for (; *str; str++) {
|
||||
unsigned char c = *str;
|
||||
|
||||
if (isalnum(c) || c == '_')
|
||||
continue;
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int suci_init_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *package, char *section, char *option, char *value)
|
||||
{
|
||||
memset(ptr, 0, sizeof(struct uci_ptr));
|
||||
|
||||
/* value */
|
||||
if (value) {
|
||||
ptr->value = value;
|
||||
}
|
||||
ptr->package = package;
|
||||
if (!ptr->package)
|
||||
goto error;
|
||||
|
||||
ptr->section = section;
|
||||
if (!ptr->section) {
|
||||
ptr->target = UCI_TYPE_PACKAGE;
|
||||
goto lastval;
|
||||
}
|
||||
|
||||
ptr->option = option;
|
||||
if (!ptr->option) {
|
||||
ptr->target = UCI_TYPE_SECTION;
|
||||
goto lastval;
|
||||
} else {
|
||||
ptr->target = UCI_TYPE_OPTION;
|
||||
}
|
||||
|
||||
lastval:
|
||||
if (ptr->section && !suci_validate_section(ptr->section))
|
||||
ptr->flags |= UCI_LOOKUP_EXTENDED;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void suci_print_list(struct uci_list *uh, char **val, char *delimiter)
|
||||
{
|
||||
struct uci_element *e;
|
||||
static char buffer[512];
|
||||
char *buf = buffer;
|
||||
*buf = '\0';
|
||||
|
||||
uci_foreach_element(uh, e) {
|
||||
if (*buf) {
|
||||
strcat(buf, delimiter);
|
||||
strcat(buf, e->name);
|
||||
}
|
||||
else {
|
||||
strcpy(buf, e->name);
|
||||
}
|
||||
}
|
||||
*val = buf;
|
||||
}
|
||||
|
||||
char *suci_get_value(char *package, char *section, char *option)
|
||||
{
|
||||
struct uci_ptr ptr;
|
||||
char *val = "";
|
||||
|
||||
if (!section || !option)
|
||||
return val;
|
||||
|
||||
if (suci_init_ptr(uci_ctx, &ptr, package, section, option, NULL))
|
||||
return val;
|
||||
|
||||
if (uci_lookup_ptr(uci_ctx, &ptr, NULL, true) != UCI_OK)
|
||||
return val;
|
||||
|
||||
if (!ptr.o)
|
||||
return val;
|
||||
|
||||
if(ptr.o->type == UCI_TYPE_LIST) {
|
||||
suci_print_list(&ptr.o->v.list, &val, " ");
|
||||
return val;
|
||||
}
|
||||
|
||||
if (ptr.o->v.string)
|
||||
return ptr.o->v.string;
|
||||
else
|
||||
return val;
|
||||
}
|
||||
|
||||
char *suci_set_value(char *package, char *section, char *option, char *value)
|
||||
{
|
||||
struct uci_ptr ptr;
|
||||
int ret = UCI_OK;
|
||||
|
||||
if (!section)
|
||||
return "";
|
||||
|
||||
if (suci_init_ptr(uci_ctx, &ptr, package, section, option, value))
|
||||
return "";
|
||||
|
||||
if (uci_lookup_ptr(uci_ctx, &ptr, NULL, true) != UCI_OK)
|
||||
return "";
|
||||
|
||||
uci_set(uci_ctx, &ptr);
|
||||
|
||||
if (ret == UCI_OK)
|
||||
ret = uci_save(uci_ctx, ptr.p);
|
||||
|
||||
if (ptr.o && ptr.o->v.string)
|
||||
return ptr.o->v.string;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/*************************---/var/state--***************************/
|
||||
|
||||
char *suci_get_value_state(char *package, char *section, char *option)
|
||||
{
|
||||
char *val;
|
||||
struct uci_context *save_uci_ctx = uci_ctx;
|
||||
uci_ctx = uci_ctx_state;
|
||||
val = suci_get_value(package, section, option);
|
||||
uci_ctx = save_uci_ctx;
|
||||
return val;
|
||||
}
|
||||
|
||||
char *suci_set_value_state(char *package, char *section, char *option, char *value)
|
||||
{
|
||||
char *val;
|
||||
struct uci_context *save_uci_ctx = uci_ctx;
|
||||
uci_ctx = uci_ctx_state;
|
||||
val = suci_set_value(package, section, option, value);
|
||||
uci_ctx = save_uci_ctx;
|
||||
return val;
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
/* TR-069 STUN client software
|
||||
* Copyright (C) 2020 PIVA SOFTWARE <www.pivasoftware.com> - All Rights Reserved
|
||||
* Author: Omar Kallel <omar.kallel@pivasoftware.com>
|
||||
*/
|
||||
|
||||
#ifndef __CONFIG_H
|
||||
#define __CONFIG_H
|
||||
|
||||
#include <uci.h>
|
||||
#include "log.h"
|
||||
|
||||
#define VAR_STATE "/var/state"
|
||||
#define DEFAULT_SERVERPORT 3478
|
||||
#define DEFAULT_CLIENTPORT 7547
|
||||
#define DEFAULT_MINKEEPALIVE 30
|
||||
#define DEFAULT_RETRYTIME 3
|
||||
#define DEFAULT_MAXKEEPALIVE 3600
|
||||
#define DEFAULT_LOGLEVEL SINFO
|
||||
|
||||
struct stun_config {
|
||||
char *server_address;
|
||||
char *username;
|
||||
char *password;
|
||||
int server_port;
|
||||
int client_port;
|
||||
int max_keepalive;
|
||||
int min_keepalive;
|
||||
int loglevel;
|
||||
};
|
||||
|
||||
extern struct stun_config conf;
|
||||
|
||||
int config_init(void);
|
||||
int config_fini(void);
|
||||
|
||||
int suci_init(void);
|
||||
int suci_fini(void);
|
||||
void suci_print_list(struct uci_list *uh, char **val, char *delimiter);
|
||||
char *suci_get_value(char *package, char *section, char *option);
|
||||
char *suci_set_value(char *package, char *section, char *option, char *value);
|
||||
char *suci_get_value_state(char *package, char *section, char *option);
|
||||
char *suci_set_value_state(char *package, char *section, char *option, char *value);
|
||||
|
||||
#endif //__CONFIG_H
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* log.c : conatains function used log traces
|
||||
*
|
||||
* Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
|
||||
*
|
||||
* Author: Omar Kallel <omar.kallel@pivasoftware.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "config.h"
|
||||
|
||||
static const int log_syslogmap[] = {
|
||||
[SCRIT] = LOG_CRIT,
|
||||
[SWARNING] = LOG_WARNING,
|
||||
[SNOTICE] = LOG_NOTICE,
|
||||
[SINFO] = LOG_INFO,
|
||||
[SDEBUG] = LOG_DEBUG
|
||||
};
|
||||
|
||||
static const char* log_str[] = {
|
||||
[SCRIT] = "CRITICAL",
|
||||
[SWARNING] = "WARNING",
|
||||
[SNOTICE] = "NOTICE",
|
||||
[SINFO] = "INFO",
|
||||
[SDEBUG] = "DEBUG"
|
||||
};
|
||||
|
||||
void stun_log(int priority, const char *format, ...)
|
||||
{
|
||||
va_list vl;
|
||||
|
||||
if (priority <= conf.loglevel) {
|
||||
time_t t = time(NULL);
|
||||
struct tm tm = *localtime(&t);
|
||||
va_start(vl, format);
|
||||
printf("%d-%02d-%02d %02d:%02d:%02d [stun] %s - ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, log_str[priority]);
|
||||
vprintf(format, vl);
|
||||
va_end(vl);
|
||||
printf("\n");
|
||||
|
||||
openlog("stun", 0, LOG_DAEMON);
|
||||
va_start(vl, format);
|
||||
vsyslog(log_syslogmap[priority], format, vl);
|
||||
va_end(vl);
|
||||
closelog();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
/* TR-069 STUN client software
|
||||
* Copyright (C) 2020 PIVA SOFTWARE <www.pivasoftware.com> - All Rights Reserved
|
||||
* Author: Omar Kallel <omar.kallel@pivasoftware.com>
|
||||
*/
|
||||
|
||||
#ifndef __SLOG_H
|
||||
#define __SLOG_H
|
||||
|
||||
enum stun_log_level_enum {
|
||||
SCRIT,
|
||||
SWARNING,
|
||||
SNOTICE,
|
||||
SINFO,
|
||||
SDEBUG,
|
||||
__MAX_SLOG
|
||||
};
|
||||
|
||||
void stun_log(int priority, const char *format, ...);
|
||||
|
||||
#endif //__SLOG_H
|
||||
687
stun/src/stun.c
687
stun/src/stun.c
|
|
@ -1,687 +0,0 @@
|
|||
/*
|
||||
* stun.c -- the main file of stun application
|
||||
*
|
||||
* Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
|
||||
*
|
||||
* Author: Omar Kallel <omar.kallel@pivasoftware.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
* TR-069 STUN client software
|
||||
* Copyright (C) 2020 PIVA SOFTWARE <www.pivasoftware.com> - All Rights Reserved
|
||||
* Author: Mohamed Kallel <mohamed.kallel@pivasoftware.com>
|
||||
* Omar Kallel <omar.kallel@pivasoftware.com>
|
||||
* Anis Ellouze <anis.ellouze@pivasoftware.com>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <pthread.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/un.h>
|
||||
#include <stdlib.h>
|
||||
#include <libubox/uloop.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <string.h>
|
||||
#include <ifaddrs.h>
|
||||
|
||||
#include "stun.h"
|
||||
#include "config.h"
|
||||
#include "ubus.h"
|
||||
|
||||
struct env_var env = {0};
|
||||
int keepalive_timeout = DEFAULT_MINKEEPALIVE;
|
||||
int retry_timeout = DEFAULT_RETRYTIME;
|
||||
int bindcrreusaddr = 1;
|
||||
int bindcrreusport = 1;
|
||||
const char *BBFCR = "dslforum.org/TR-111 ";
|
||||
|
||||
static void stun_notify_cb(struct uloop_timeout *timeout);
|
||||
static void stun_inform_cb(struct uloop_timeout *timeout);
|
||||
static void listening_crport_cb(struct uloop_timeout *timeout);
|
||||
static void binding_request_crport_cb(struct uloop_timeout *timeout);
|
||||
|
||||
|
||||
static struct udp_listen listen_crport = {
|
||||
.fd = -1,
|
||||
.utimer = {.cb = listening_crport_cb}
|
||||
};
|
||||
static struct binding_request br_crport = {
|
||||
.binding_cr = 1,
|
||||
.udp_listen = &listen_crport,
|
||||
.utimer = {.cb = binding_request_crport_cb}
|
||||
};
|
||||
static struct binding_request br_crport_keepalive = {
|
||||
.is_keealive = 1,
|
||||
.binding_cr = 1,
|
||||
.udp_listen = &listen_crport,
|
||||
.utimer = {.cb = binding_request_crport_cb}
|
||||
};
|
||||
|
||||
struct uloop_timeout stun_notify_timer = {.cb = stun_notify_cb};
|
||||
struct uloop_timeout stun_inform_timer = {.cb = stun_inform_cb};
|
||||
|
||||
void stun_notify(int afterms)
|
||||
{
|
||||
uloop_timeout_set(&stun_notify_timer, afterms);
|
||||
}
|
||||
|
||||
void stun_inform(int afterms)
|
||||
{
|
||||
uloop_timeout_set(&stun_inform_timer, afterms);
|
||||
}
|
||||
|
||||
|
||||
static void stun_notify_cb(struct uloop_timeout *timeout)
|
||||
{
|
||||
stun_log(SINFO, "ubus call tr069 notify");
|
||||
if (subus_call("tr069", "notify", 0, UBUS_ARGS{}) < 0) {
|
||||
stun_log(SINFO, "ubus call tr069 notify failed! retry after 1s");
|
||||
stun_notify(1000);
|
||||
}
|
||||
}
|
||||
|
||||
static void stun_inform_cb(struct uloop_timeout *timeout)
|
||||
{
|
||||
stun_log(SINFO, "ubus call tr069 inform '{\"event\": \"6 connection request\"}'");
|
||||
if (subus_call("tr069", "inform", 1, UBUS_ARGS{{"event", "6 connection request"}}) < 0) {
|
||||
stun_log(SINFO, "ubus call tr069 inform '{\"event\": \"6 connection request\"}' failed! retry after 1s");
|
||||
stun_inform(1000);
|
||||
}
|
||||
}
|
||||
|
||||
static int stunid_cmp(stunid *left, stunid *right)
|
||||
{
|
||||
return memcmp(left, right, sizeof(*left));
|
||||
}
|
||||
|
||||
static void *stunid_cpy(stunid *left, stunid *right)
|
||||
{
|
||||
return memcpy(left, right, sizeof(*left));
|
||||
}
|
||||
|
||||
static void stunid_rand(stunid *id)
|
||||
{
|
||||
int i;
|
||||
srand(time(NULL));
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
id->id[i] = rand();
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t timeout_recvfrom(int sock, char *buf, int length, struct sockaddr_in *connection, int timeoutinseconds)
|
||||
{
|
||||
fd_set socks;
|
||||
ssize_t r = 0;
|
||||
struct timeval t = {0};
|
||||
int clen = sizeof(*connection);
|
||||
|
||||
stun_log(SDEBUG, "udp revcfrom, timeout: %ds", timeoutinseconds);
|
||||
|
||||
FD_ZERO(&socks);
|
||||
FD_SET(sock, &socks);
|
||||
t.tv_sec = timeoutinseconds;
|
||||
if (select(sock + 1, &socks, NULL, NULL, &t) &&
|
||||
(r = recvfrom(sock, buf, length, 0, (struct sockaddr *)connection, (socklen_t *)&clen)) != -1) {
|
||||
return r;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int stun_send(int s, char *buf)
|
||||
{
|
||||
struct stun_header *sh;
|
||||
struct hostent *he;
|
||||
struct sockaddr_in dst = {0};
|
||||
|
||||
sh = (struct stun_header *)buf;
|
||||
if ((he = gethostbyname(conf.server_address)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(&(dst.sin_addr), he->h_addr_list[0], he->h_length);
|
||||
dst.sin_port = htons(conf.server_port);
|
||||
dst.sin_family = AF_INET;
|
||||
|
||||
stun_log(SINFO, "send STUN message to %s:%u (%s:%u)", conf.server_address, conf.server_port, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port));
|
||||
|
||||
return sendto(s, buf, ntohs(sh->len) + sizeof(*sh), 0, (struct sockaddr *)&dst, sizeof(dst));
|
||||
}
|
||||
|
||||
static int net_socket(int srcport)
|
||||
{
|
||||
int sock = -1;
|
||||
stun_log(SINFO, "Open UDP socket");
|
||||
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
if (sock >= 0) {
|
||||
if (srcport > 0) {
|
||||
struct sockaddr_in bindcraddr = {0};
|
||||
int i = 0;
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &bindcrreusaddr, sizeof(int)) < 0) {
|
||||
stun_log(SWARNING, "setsockopt(SO_REUSEADDR) failed");
|
||||
}
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &bindcrreusport, sizeof(int)) < 0) {
|
||||
stun_log(SWARNING, "setsockopt(SO_REUSEPORT) failed");
|
||||
}
|
||||
bindcraddr.sin_family = AF_INET;
|
||||
bindcraddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
bindcraddr.sin_port = htons((unsigned short)srcport);
|
||||
for(;i<9;i++)
|
||||
{
|
||||
if (bind(sock, (struct sockaddr *)&bindcraddr, sizeof(bindcraddr)) < 0) {
|
||||
continue;
|
||||
}
|
||||
stun_log(SINFO, "binding socket source port to %u", srcport);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);
|
||||
fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
|
||||
}
|
||||
return sock;
|
||||
}
|
||||
|
||||
static void stun_close_socket(struct udp_listen *udp_listen)
|
||||
{
|
||||
uloop_timeout_cancel(&udp_listen->utimer);
|
||||
if (udp_listen->fd > 0) {
|
||||
stun_log(SINFO, "STUN close socket %d", udp_listen->fd);
|
||||
close(udp_listen->fd);
|
||||
}
|
||||
udp_listen->fd = -1;
|
||||
}
|
||||
|
||||
static void stun_socket(struct udp_listen *udp_listen)
|
||||
{
|
||||
|
||||
if (udp_listen->fd > 0) {
|
||||
stun_close_socket(udp_listen);
|
||||
}
|
||||
udp_listen->fd = net_socket(conf.client_port);
|
||||
stun_log(SINFO, "STUN new socket %d", udp_listen->fd);
|
||||
uloop_timeout_set(&udp_listen->utimer, 0);
|
||||
}
|
||||
|
||||
static int trailing_buffer_alloc(int mp, char *buf, int len, char trail, char **bufm, int *mlen)
|
||||
{
|
||||
*bufm = NULL;
|
||||
*mlen = len % mp;
|
||||
*mlen = len + (*mlen ? (mp - *mlen) : 0);
|
||||
*bufm = calloc(1, *mlen);
|
||||
if (*bufm == NULL)
|
||||
return -1;
|
||||
memcpy(*bufm, buf, len);
|
||||
if (trail) {
|
||||
while(len < *mlen) {
|
||||
(*bufm)[len++] = trail;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int append_attribute_buffer(unsigned char **start, char *buf, int len, unsigned short attr_type, int free)
|
||||
{
|
||||
if ((sizeof(struct stun_attribute) + len) > free)
|
||||
return -1;
|
||||
struct stun_attribute *sa = (struct stun_attribute *)*start;
|
||||
sa->len = htons((unsigned short)len);
|
||||
sa->type = htons(attr_type);
|
||||
memcpy(sa->value, buf, len);
|
||||
*start += sizeof(struct stun_attribute) + len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stun_hmac(int trailing_mp, unsigned char *data, int len, char *password, char *hmac)
|
||||
{
|
||||
char *bufmp = NULL;
|
||||
int lenmp;
|
||||
unsigned char* digest;
|
||||
|
||||
if (trailing_mp) {
|
||||
if (trailing_buffer_alloc(trailing_mp, (char *)data, len, 0, &bufmp, &lenmp))
|
||||
return -1;
|
||||
digest = HMAC(EVP_sha1(), password, strlen(password), (unsigned char *)bufmp, lenmp, NULL, NULL);
|
||||
free(bufmp);
|
||||
}
|
||||
else {
|
||||
digest = HMAC(EVP_sha1(), password, strlen(password), data, len, NULL, NULL);
|
||||
}
|
||||
|
||||
memcpy(hmac, digest, 20);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hex_to_str(char *hex, int len, char *str)
|
||||
{
|
||||
while (len--) {
|
||||
sprintf(str, "%02X", *hex++);
|
||||
str += 2;
|
||||
}
|
||||
}
|
||||
|
||||
static int generate_stun_packet(struct binding_request *br, char *req_buf, int maxlen)
|
||||
{
|
||||
struct stun_header *req;
|
||||
unsigned char *stunmsg;
|
||||
|
||||
req = (struct stun_header *) req_buf;
|
||||
stunmsg = req->stunmsg;
|
||||
|
||||
stun_log(SINFO, "STUN generate BINDING-REQUEST");
|
||||
req->type = htons(BINDING_REQUSET);
|
||||
stunid_rand(&(req->id));
|
||||
stunid_cpy(&(br->id), &(req->id));
|
||||
stun_log(SINFO, "STUN request id: %d%d%d%d", req->id.id[0], req->id.id[1], req->id.id[2], req->id.id[3]);
|
||||
if (conf.username) {
|
||||
char *buf4;
|
||||
int len4;
|
||||
if (trailing_buffer_alloc(4, conf.username, strlen(conf.username), ' ', &buf4, &len4))
|
||||
return -1;
|
||||
append_attribute_buffer(&stunmsg, buf4, len4, ATTR_USERNAME, (maxlen - (stunmsg - (unsigned char *)req)));
|
||||
stun_log(SINFO, "STUN append USERNAME: **%.*s**", len4, buf4);
|
||||
free(buf4);
|
||||
}
|
||||
if (br->binding_cr) {
|
||||
stun_log(SINFO, "STUN append CONNECTION-REQUEST-BINDING: **%s**", BBFCR);
|
||||
append_attribute_buffer(&stunmsg, (char *)BBFCR, strlen(BBFCR), ATTR_CONNECTION_REQUEST_BINDING, (maxlen - (stunmsg - (unsigned char *)req)));
|
||||
}
|
||||
if (br->binding_change) {
|
||||
stun_log(SINFO, "STUN append BINDING-CHANGE");
|
||||
append_attribute_buffer(&stunmsg, "", 0, ATTR_BINDING_CHANGE, (maxlen - (stunmsg - (unsigned char *)req)));
|
||||
}
|
||||
if (br->msg_integrity) {
|
||||
if (conf.username) {
|
||||
char *password;
|
||||
char hmac[20] = {0};
|
||||
char hmacstr[64];
|
||||
req->len = htons((stunmsg - (unsigned char *)req) - sizeof(struct stun_header) + sizeof(struct stun_attribute) + 20);
|
||||
password = conf.password ? conf.password : "";
|
||||
stun_hmac(64, (unsigned char *)req, stunmsg - (unsigned char *)req, password, hmac);
|
||||
append_attribute_buffer(&stunmsg, hmac, sizeof(hmac), ATTR_MESSAGE_INTEGRITY, (maxlen - (stunmsg - (unsigned char *)req)));
|
||||
hex_to_str(hmac, 20, hmacstr);
|
||||
stun_log(SINFO, "STUN append MESSAGE-INTEGRITY: ***%s***", hmacstr);
|
||||
}
|
||||
else {
|
||||
req->len = htons((stunmsg - (unsigned char *)req) - sizeof(struct stun_header));
|
||||
br->msg_integrity = 0;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
req->len = htons((stunmsg - (unsigned char *)req) - sizeof(struct stun_header));
|
||||
}
|
||||
stun_log(SINFO, "STUN request length: %d", ntohs(req->len));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stun_get_mapped_address(char *buf, unsigned int *ip, unsigned short *port)
|
||||
{
|
||||
struct stun_header *sh = (struct stun_header *)buf;
|
||||
struct stun_attribute *sa = (struct stun_attribute *)sh->stunmsg;
|
||||
char *p;
|
||||
while (((char *)sa - (char *)sh - sizeof(*sh)) < ntohs(sh->len)) {
|
||||
if(ntohs(sa->type) == ATTR_MAPPED_ADDRESS) {
|
||||
struct stun_address *ma = (struct stun_address *)sa->value;
|
||||
*port = ma->port;
|
||||
*ip = ma->address;
|
||||
return 0;
|
||||
}
|
||||
p = (char *)sa;
|
||||
p += sizeof(struct stun_attribute) + ntohs(sa->len);
|
||||
sa = (struct stun_attribute *)p;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int stun_get_error_code(char *buf)
|
||||
{
|
||||
struct stun_header *sh = (struct stun_header *)buf;
|
||||
struct stun_attribute *sa = (struct stun_attribute *)sh->stunmsg;
|
||||
char *p;
|
||||
|
||||
while (((char *)sa - (char *)sh - sizeof(*sh)) < ntohs(sh->len)) {
|
||||
if(ntohs(sa->type) == ATTR_ERROR_CODE) {
|
||||
unsigned int class, number;
|
||||
unsigned int ui = ntohl(*((unsigned int *)sa->value));
|
||||
class = (ui >> 8) & 0x7;
|
||||
number = ui & 0xff;
|
||||
return (int)(class * 100 + number);
|
||||
}
|
||||
p = (char *)sa;
|
||||
p += sizeof(struct stun_attribute) + ntohs(sa->len);
|
||||
sa = (struct stun_attribute *)p;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void handle_udp_cr(char *resp_buf)
|
||||
{
|
||||
char *str;
|
||||
char un[64], cn[64], sig[64], buf[256];
|
||||
char *crusername;
|
||||
char *crpassword;
|
||||
unsigned int crid = 0, ts = 0;
|
||||
int valid = 1;
|
||||
|
||||
stun_log(SINFO, "Handle UDP Connection Request");
|
||||
|
||||
if ((str = strstr(resp_buf, "ts="))) {
|
||||
sscanf(str, "ts=%u", &ts);
|
||||
stun_log(SINFO, "UDP CR ts = %u", ts);
|
||||
}
|
||||
else {
|
||||
stun_log(SWARNING, "UDP CR ts not found");
|
||||
return;
|
||||
}
|
||||
if ((str = strstr(resp_buf, "id="))) {
|
||||
sscanf(str, "id=%u", &crid);
|
||||
stun_log(SINFO, "UDP CR id = %u", crid);
|
||||
}
|
||||
else {
|
||||
return;
|
||||
stun_log(SWARNING, "UDP CR id not found");
|
||||
}
|
||||
if (crid && ts && crid != env.last_crid && ts > env.last_ts) {
|
||||
stun_log(SINFO, "NEW UDP CR");
|
||||
env.last_crid = crid;
|
||||
env.last_ts = ts;
|
||||
if ((str = strstr(resp_buf, "un="))) {
|
||||
sscanf(str, "un=%63[^?& \t\n\r]", un);
|
||||
stun_log(SINFO, "UDP CR un = %s", un);
|
||||
}
|
||||
else {
|
||||
stun_log(SWARNING, "UDP CR un not found");
|
||||
return;
|
||||
}
|
||||
if ((str = strstr(resp_buf, "cn="))) {
|
||||
sscanf(str, "cn=%63[^?& \t\n\r]", cn);
|
||||
stun_log(SINFO, "UDP CR cn = %s", cn);
|
||||
}
|
||||
else {
|
||||
stun_log(SWARNING, "UDP CR cn not found");
|
||||
return;
|
||||
}
|
||||
if ((str = strstr(resp_buf, "sig="))) {
|
||||
sscanf(str, "sig=%63[^?& \t\n\r]",sig);
|
||||
stun_log(SINFO, "UDP CR sig = %s", sig);
|
||||
}
|
||||
else {
|
||||
stun_log(SWARNING, "UDP CR sig not found");
|
||||
return;
|
||||
}
|
||||
suci_init();
|
||||
crusername = suci_get_value("cwmp", "cpe", "userid");
|
||||
crpassword = suci_get_value("cwmp", "cpe", "password");
|
||||
if (*crusername && *crpassword) {
|
||||
if (strcmp(crusername, un) != 0) {
|
||||
stun_log(SINFO, "UDP CR username mismatch!");
|
||||
valid = 0;
|
||||
}
|
||||
else {
|
||||
char hmac[20], hmacstr[64];
|
||||
snprintf(buf, sizeof(buf), "%u%u%s%s", ts, crid, un, cn);
|
||||
stun_hmac(0, (unsigned char *)buf, strlen(buf), crpassword, hmac);
|
||||
hex_to_str(hmac, 20, hmacstr);
|
||||
if (strcasecmp(hmacstr, sig) != 0) {
|
||||
stun_log(SINFO, "UDP CR sig mismatch!");
|
||||
valid = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
suci_fini();
|
||||
if (valid) {
|
||||
stun_inform(0);
|
||||
}
|
||||
} else {
|
||||
if (!ts || !crid)
|
||||
stun_log(SINFO, "UDP CR ts or id not found");
|
||||
else
|
||||
stun_log(SINFO, "UDP CR ts is old or id is already received");
|
||||
}
|
||||
}
|
||||
|
||||
static void save_udpcr_var_state(unsigned int ip, unsigned short port)
|
||||
{
|
||||
struct in_addr ip_addr;
|
||||
char buf[64];
|
||||
|
||||
ip_addr.s_addr = env.address;
|
||||
snprintf(buf, sizeof(buf), "%s:%d", inet_ntoa(ip_addr), ntohs(env.port));
|
||||
stun_log(SINFO, "Save New UDPConnectionRequestAddress to /var/state %s", buf);
|
||||
suci_init();
|
||||
suci_set_value_state("stun", "stun", "crudp_address", buf);
|
||||
suci_fini();
|
||||
}
|
||||
|
||||
static int is_udpcr_changed(unsigned int ip, unsigned short port)
|
||||
{
|
||||
struct in_addr ip_addr;
|
||||
char buf[64];
|
||||
char *v;
|
||||
int changed = 0;
|
||||
|
||||
ip_addr.s_addr = ip;
|
||||
snprintf(buf, sizeof(buf), "%s:%d", inet_ntoa(ip_addr), ntohs(port));
|
||||
suci_init();
|
||||
v = suci_get_value_state("stun", "stun", "crudp_address");
|
||||
if (strcmp(buf, v) != 0)
|
||||
changed = 1;
|
||||
suci_fini();
|
||||
return changed;
|
||||
}
|
||||
|
||||
static void save_natdetected_var_state(unsigned int ip)
|
||||
{
|
||||
struct ifaddrs * ifaddrlist = NULL;
|
||||
struct ifaddrs * ifa = NULL;
|
||||
int islocal = 0;
|
||||
char *nd;
|
||||
|
||||
getifaddrs(&ifaddrlist);
|
||||
|
||||
for (ifa = ifaddrlist; ifa != NULL; ifa = ifa->ifa_next) {
|
||||
if (ifa ->ifa_addr && ifa ->ifa_addr->sa_family == AF_INET) {
|
||||
if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == ip) {
|
||||
islocal = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ifaddrlist != NULL)
|
||||
freeifaddrs(ifaddrlist);
|
||||
|
||||
suci_init();
|
||||
nd = suci_get_value_state("stun", "stun", "nat_detected");
|
||||
|
||||
if (islocal && *nd != '\0') {
|
||||
stun_log(SINFO, "Device is not behind NAT, set NATDetected to false");
|
||||
suci_set_value_state("stun", "stun", "nat_detected", "");
|
||||
}
|
||||
else if (!islocal && *nd == '\0') {
|
||||
stun_log(SINFO, "Device is behind NAT, set NATDetected to true");
|
||||
suci_set_value_state("stun", "stun", "nat_detected", "1");
|
||||
}
|
||||
suci_fini();
|
||||
}
|
||||
|
||||
static void binding_request_crport_cb(struct uloop_timeout *timeout)
|
||||
{
|
||||
struct binding_request *br;
|
||||
struct udp_listen *udp_listen;
|
||||
char req_buf[2048] = {0};
|
||||
int r;
|
||||
|
||||
|
||||
br = binding_request_entry(timeout);
|
||||
udp_listen = br->udp_listen;
|
||||
|
||||
udp_listen->br = br;
|
||||
|
||||
stun_log(SINFO, "Binding Request cb start %s", br->is_keealive ? "(KeepAlive)" : "");
|
||||
|
||||
if (udp_listen->fd <= 0) {
|
||||
stun_socket(udp_listen);
|
||||
}
|
||||
|
||||
if (br->resp_success > 0)
|
||||
br->resp_success = 0;
|
||||
|
||||
if (generate_stun_packet(br, req_buf, sizeof(req_buf) - 1)) {
|
||||
br->retry_interval = (br->retry_interval) ? 2 * br->retry_interval : retry_timeout;
|
||||
br->retry_interval = (br->retry_interval > 1500) ? 1500 : br->retry_interval;
|
||||
uloop_timeout_set(&br->utimer, br->retry_interval * 1000);
|
||||
return;
|
||||
}
|
||||
r = stun_send(udp_listen->fd, req_buf);
|
||||
if (r < 0) {
|
||||
stun_close_socket(udp_listen);
|
||||
udp_listen->br = NULL;
|
||||
br->retry_interval = (br->retry_interval) ? 2 * br->retry_interval : retry_timeout;
|
||||
br->retry_interval = (br->retry_interval > 1500) ? 1500 : br->retry_interval;
|
||||
stun_log(SINFO, "Failed send of Binding Request! retry in %ds", br->retry_interval);
|
||||
uloop_timeout_set(timeout, br->retry_interval * 1000);
|
||||
}
|
||||
else {
|
||||
br->retry_interval = 0;
|
||||
stun_log(SINFO, "Success send of Binding Request.");
|
||||
stun_log(SINFO, "Start KeepAlive Binding Request in %ds.", keepalive_timeout);
|
||||
uloop_timeout_set(&br_crport_keepalive.utimer, keepalive_timeout * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
static void listening_crport_cb(struct uloop_timeout *timeout)
|
||||
{
|
||||
struct udp_listen *udp_listen;
|
||||
struct sockaddr_in src = {0};
|
||||
char resp_buf[2048] = {0};
|
||||
unsigned int ip = 0;
|
||||
unsigned short port = 0;
|
||||
int r;
|
||||
|
||||
stun_log(SDEBUG, "Binding listening CR cb start");
|
||||
udp_listen = udp_listen_entry(timeout);
|
||||
if (udp_listen->fd < 0) {
|
||||
stun_log(SINFO, "Binding listening CR: Socket = -1");
|
||||
uloop_timeout_set(timeout, 19);
|
||||
return;
|
||||
}
|
||||
r = timeout_recvfrom(udp_listen->fd, resp_buf, sizeof(resp_buf) - 1, &src, 1);
|
||||
if (r > 0) {
|
||||
stun_log(SINFO, "Binding listening CR: get UDP packet");
|
||||
struct stun_header *sh = (struct stun_header *)resp_buf;
|
||||
if (ntohs(sh->type) == BINDING_ERROR) {
|
||||
int code = stun_get_error_code(resp_buf);
|
||||
stun_log(SINFO, "get BINDING-ERROR: code is %d", code);
|
||||
if (udp_listen->br != NULL && stunid_cmp(&(sh->id), &(udp_listen->br->id)) == 0 && code == 401) {
|
||||
udp_listen->br->msg_integrity = 1;
|
||||
udp_listen->br->auth_fail++;
|
||||
stun_log(SINFO, "Cancel scheduled Keepalive Binding Request");
|
||||
uloop_timeout_cancel(&br_crport_keepalive.utimer);
|
||||
stun_log(SINFO, "Trying new Binding Request in %ds",
|
||||
(udp_listen->br->auth_fail < 3) ? 0 : (udp_listen->br->auth_fail - 2)*3);
|
||||
uloop_timeout_set(&udp_listen->br->utimer,
|
||||
(udp_listen->br->auth_fail < 3) ? 0 : ((udp_listen->br->auth_fail - 2) * 3000));
|
||||
udp_listen->br = NULL;
|
||||
}
|
||||
else if (code != 401) {
|
||||
stun_log(SINFO, "Unsupported error code");
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
else if (ntohs(sh->type) == BINDING_RESPONSE) {
|
||||
struct in_addr ip_addr;
|
||||
stun_log(SINFO, "get BINDING-RESPONSE");
|
||||
if (udp_listen->br != NULL && stunid_cmp(&(sh->id), &(udp_listen->br->id)) == 0) {
|
||||
udp_listen->br->resp_success = 1;
|
||||
udp_listen->br->msg_integrity = 0;
|
||||
udp_listen->br->auth_fail = 0;
|
||||
stun_get_mapped_address(resp_buf, &ip, &port);
|
||||
ip_addr.s_addr = ip;
|
||||
stun_log(SINFO, "Mapped Address is: %s:%u", inet_ntoa(ip_addr), ntohs(port));
|
||||
save_natdetected_var_state(ip);
|
||||
if (is_udpcr_changed(ip, port)) {
|
||||
env.address = ip;
|
||||
env.port = port;
|
||||
udp_listen->br->resp_success = 0;
|
||||
udp_listen->br->binding_change = 1;
|
||||
uloop_timeout_set(&udp_listen->br->utimer, 0);
|
||||
save_udpcr_var_state(ip, port);
|
||||
stun_notify(0);
|
||||
}
|
||||
else {
|
||||
udp_listen->br = NULL;
|
||||
}
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
else if (strstr(resp_buf, "http") || strstr(resp_buf, "HTTP")) {
|
||||
stun_log(SINFO, "get UDP Connection Request");
|
||||
handle_udp_cr(resp_buf);
|
||||
}
|
||||
else {
|
||||
stun_log(SINFO, "get non supported STUN/UDP message");
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* timed out */
|
||||
if (!udp_listen->br || udp_listen->br->resp_success == 1)
|
||||
goto end;
|
||||
stun_log(SINFO, "Timed OUT!");
|
||||
udp_listen->br->resp_success--;
|
||||
if (udp_listen->br->resp_success < -2) {
|
||||
int rs = -udp_listen->br->resp_success;
|
||||
if ((rs % 9) == 0) {
|
||||
stun_log(SINFO, "Retry sending in a new socket");
|
||||
stun_close_socket(udp_listen);
|
||||
uloop_timeout_set(&udp_listen->br->utimer, 0);
|
||||
udp_listen->br = NULL;
|
||||
}
|
||||
else if ((rs % 3) == 0) {
|
||||
stun_log(SINFO, "Retry sending.");
|
||||
uloop_timeout_set(&udp_listen->br->utimer, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
end:
|
||||
uloop_timeout_set(timeout, 1);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
stun_log(SINFO, "Start stund daemon");
|
||||
config_init();
|
||||
keepalive_timeout = conf.min_keepalive;
|
||||
|
||||
uloop_init();
|
||||
uloop_timeout_set(&br_crport.utimer, 100);
|
||||
uloop_run();
|
||||
uloop_done();
|
||||
|
||||
config_fini();
|
||||
stun_log(SINFO, "Stop stund daemon");
|
||||
return 0;
|
||||
}
|
||||
106
stun/src/stun.h
106
stun/src/stun.h
|
|
@ -1,106 +0,0 @@
|
|||
#ifndef _STUN_H
|
||||
#define _STUN_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <libubox/uloop.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef container_of
|
||||
#define container_of(ptr, type, member) \
|
||||
({ \
|
||||
const typeof(((type *) NULL)->member) *__mptr = (ptr); \
|
||||
(type *) ((char *) __mptr - offsetof(type, member)); \
|
||||
})
|
||||
#endif
|
||||
|
||||
#define binding_request_entry(X) container_of(X, struct binding_request, utimer)
|
||||
#define udp_listen_entry(X) container_of(X, struct udp_listen, utimer)
|
||||
|
||||
#define BINDING_REQUSET 0x0001
|
||||
#define BINDING_RESPONSE 0x0101
|
||||
#define BINDING_ERROR 0x0111
|
||||
|
||||
#define ATTR_MAPPED_ADDRESS 0x0001
|
||||
#define ATTR_RESPONSE_ADDRESS 0x0002
|
||||
#define ATTR_CHANGE_REQUEST 0x0003
|
||||
#define ATTR_SOURCE_ADDRESS 0x0004
|
||||
#define ATTR_CHANGED_ADDRESS 0x0005
|
||||
#define ATTR_USERNAME 0x0006
|
||||
#define ATTR_PASSWORD 0x0007
|
||||
#define ATTR_MESSAGE_INTEGRITY 0x0008
|
||||
#define ATTR_ERROR_CODE 0x0009
|
||||
#define ATTR_UNKNOWN_ATTRIBUTES 0x000a
|
||||
#define ATTR_REFLECTED_FROM 0x000b
|
||||
#define ATTR_CONNECTION_REQUEST_BINDING 0xC001
|
||||
#define ATTR_BINDING_CHANGE 0xC002
|
||||
|
||||
#define STUN_HEADER_LEN 20
|
||||
|
||||
struct binding_request;
|
||||
|
||||
typedef struct { unsigned int id[4]; } __attribute__((packed)) stunid;
|
||||
|
||||
struct udp_listen {
|
||||
stunid expected_id;
|
||||
int fd;
|
||||
struct uloop_timeout utimer;
|
||||
struct binding_request *br;
|
||||
};
|
||||
|
||||
struct binding_request {
|
||||
stunid id;
|
||||
unsigned char is_keealive;
|
||||
unsigned char msg_integrity; /* if true ==> MESSAGE-INTEGRITY should be append in the STUN msg */
|
||||
unsigned char binding_change; /* if true ==> BINDING-CHANGE should be append in the STUN msg */
|
||||
unsigned char binding_cr; /* if true ==> CONNECTION-REQUEST-BINDING should be append in the STUN msg */
|
||||
int resp_success;
|
||||
int auth_fail;
|
||||
int retry_interval;
|
||||
struct udp_listen *udp_listen;
|
||||
struct uloop_timeout utimer;
|
||||
};
|
||||
|
||||
|
||||
struct stun_header {
|
||||
unsigned short type;
|
||||
unsigned short len;
|
||||
stunid id;
|
||||
unsigned char stunmsg[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct stun_attribute {
|
||||
unsigned short type;
|
||||
unsigned short len;
|
||||
unsigned char value[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct stun_address {
|
||||
unsigned char na;
|
||||
unsigned char family;
|
||||
unsigned short port;
|
||||
unsigned int address;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct env_var {
|
||||
unsigned short port;
|
||||
unsigned int address;
|
||||
unsigned int last_ts;
|
||||
unsigned int last_crid;
|
||||
};
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _STUN_H */
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
# README #
|
||||
|
||||
In order to reach the devices that are connected behind NAT, the cwmp protocol introduces alternative method of executing Connection Request via NAT based on STUN. The stund is an implementation of STUN functionality that performs this feature.
|
||||
|
||||
## Configuration File ##
|
||||
|
||||
The stund UCI configuration is located in **'/etc/config/stun'** and contains only one section **stun**:
|
||||
|
||||
```
|
||||
config stun 'stun'
|
||||
option enable '0'
|
||||
option username 'stun'
|
||||
option password 'stun'
|
||||
option server_address 'stun.l.google.com'
|
||||
option server_port '19302'
|
||||
option min_keepalive '30'
|
||||
option max_keepalive '3600'
|
||||
option client_port 7547
|
||||
option log_level '1'
|
||||
```
|
||||
|
||||
### stun section ###
|
||||
|
||||
It defines **the stun section configuration** (like username, password, etc...). The possible options for **stun** section are listed in the table below.
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---------------- | ------- | ------------------------------------------------- |
|
||||
| `enable` | boolean | if set to **1**, the STUN client will be enabled. |
|
||||
| `username` | string | The STUN username to be used in Binding Requests. |
|
||||
| `password` | string | The STUN Password to be used in computing the MESSAGE-INTEGRITY. |
|
||||
| `server_address` | string | The host name or IP address of the STUN server to send Binding Requests. |
|
||||
| `server_port` | integer | The port number of the STUN server to send Binding Requests. |
|
||||
| `min_keepalive` | integer | The minimum period that STUN Binding Requests must be sent by the CPE for the purpose of maintaining the binding in the Gateway. |
|
||||
| `max_keepalive` | integer | The maximum period that STUN Binding Requests must be sent by the CPE for the purpose of maintaining the binding in the Gateway. |
|
||||
| `client_port` | integer | The client source port of the STUN UDP binding. |
|
||||
| `log_level` | integer | The log type to use, by default it is set to **'INFO'**. The possible types are **'EMERG', 'ALERT', 'CRITIC' ,'ERROR', 'WARNING', 'NOTICE', 'INFO' and 'DEBUG'**. |
|
||||
|
||||
## Dependencies ##
|
||||
|
||||
To successfully build stund, the following libraries are needed:
|
||||
|
||||
| Dependency | Link | License |
|
||||
| --------------- | ------------------------------------------- | -------------- |
|
||||
| libuci | https://git.openwrt.org/project/uci.git | LGPL 2.1 |
|
||||
| libubox | https://git.openwrt.org/project/libubox.git | BSD |
|
||||
| libubus | https://git.openwrt.org/project/ubus.git | LGPL 2.1 |
|
||||
| libjson-c | https://s3.amazonaws.com/json-c_releases | MIT |
|
||||
| libopenssl | http://ftp.fi.muni.cz/pub/openssl/source/ | OpenSSL |
|
||||
|
||||
108
stun/src/ubus.c
108
stun/src/ubus.c
|
|
@ -1,108 +0,0 @@
|
|||
/*
|
||||
* ubus.c -- This file conatains functions that allow to make ubus calls
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
|
||||
*
|
||||
* Author: Omar Kallel <omar.kallel@pivasoftware.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <json-c/json.h>
|
||||
#include <libubox/blobmsg_json.h>
|
||||
#include <libubus.h>
|
||||
|
||||
#include "ubus.h"
|
||||
|
||||
static struct ubus_context *ubus_ctx = NULL;
|
||||
static struct blob_buf b;
|
||||
|
||||
int subus_init(void)
|
||||
{
|
||||
ubus_ctx = ubus_connect(NULL);
|
||||
if (!ubus_ctx) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int subus_fini(void)
|
||||
{
|
||||
if (ubus_ctx) {
|
||||
ubus_free(ubus_ctx);
|
||||
}
|
||||
ubus_ctx = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sadd_json_obj(json_object *json_obj_out, char *object, char *string)
|
||||
{
|
||||
json_object *json_obj_tmp = json_object_new_string(string);
|
||||
json_object_object_add(json_obj_out, object, json_obj_tmp);
|
||||
}
|
||||
|
||||
static int subus_call_req(char *path, char *method, int argc, struct sarg sarg[])
|
||||
{
|
||||
uint32_t id;
|
||||
int i, r = 1;
|
||||
char *arg;
|
||||
|
||||
json_object *json_obj_out = json_object_new_object();
|
||||
if (json_obj_out == NULL)
|
||||
return r;
|
||||
|
||||
blob_buf_init(&b, 0);
|
||||
|
||||
if (argc) {
|
||||
for (i = 0; i < argc; i++) {
|
||||
sadd_json_obj(json_obj_out, sarg[i].key, sarg[i].val);
|
||||
}
|
||||
arg = (char *)json_object_to_json_string(json_obj_out);
|
||||
|
||||
if (!blobmsg_add_json_from_string(&b, arg)) {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (ubus_lookup_id(ubus_ctx, path, &id))
|
||||
goto end;
|
||||
|
||||
r = ubus_invoke(ubus_ctx, id, method, b.head, NULL, NULL, 1);
|
||||
|
||||
end:
|
||||
json_object_put(json_obj_out);
|
||||
blob_buf_free(&b);
|
||||
return r;
|
||||
}
|
||||
|
||||
int subus_call(char *path, char *method, int argc, struct sarg dmarg[])
|
||||
{
|
||||
int r = -1;
|
||||
subus_init();
|
||||
if (ubus_ctx) {
|
||||
r = subus_call_req(path, method, argc, dmarg);
|
||||
if (r > 0) r = -1;
|
||||
}
|
||||
subus_fini();
|
||||
return r;
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
/* TR-069 STUN client software
|
||||
* Copyright (C) 2020 PIVA SOFTWARE <www.pivasoftware.com> - All Rights Reserved
|
||||
* Author: Omar Kallel <omar.kallel@pivasoftware.com>
|
||||
*/
|
||||
|
||||
#ifndef __SUBUS_H
|
||||
#define __SUBUS_H
|
||||
|
||||
#include <libubox/blobmsg_json.h>
|
||||
#include <json-c/json.h>
|
||||
#include <libubus.h>
|
||||
|
||||
struct sarg {
|
||||
char *key;
|
||||
char *val;
|
||||
};
|
||||
|
||||
#define UBUS_ARGS (struct sarg[])
|
||||
|
||||
int subus_call(char *path, char *method, int argc, struct sarg sarg[]);
|
||||
|
||||
#endif //__SUBUS_H
|
||||
|
|
@ -7,27 +7,33 @@
|
|||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=stun
|
||||
PKG_NAME:=stunc
|
||||
PKG_VERSION:=1.0.0
|
||||
|
||||
PKG_SOURCE_VERSION:=74c8205a45a69572d0c6a2615e87c019c15f8972
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://dev.iopsys.eu/iopsys/stunc.git
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
PKG_MIRROR_HASH:=skip
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
|
||||
PKG_LICENSE:=GPL-2.0-only
|
||||
PKG_LICENSE_FILES:=LICENSE
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/$(PKG_NAME)
|
||||
SECTION:=utils
|
||||
CATEGORY:=Utilities
|
||||
SUBMENU:=TRx69
|
||||
TITLE:=BBF stun Client
|
||||
TITLE:=BBF STUN Client
|
||||
DEPENDS:=+libubus +libuci +libubox +libjson-c +libopenssl +libblobmsg-json
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/description
|
||||
CWMP STUN Client
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
$(CP) ./src/* $(PKG_BUILD_DIR)/
|
||||
BBF STUN Client
|
||||
endef
|
||||
|
||||
TARGET_CFLAGS += \
|
||||
|
|
@ -39,4 +45,4 @@ define Package/$(PKG_NAME)/install
|
|||
$(CP) ./files/* $(1)/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,$(PKG_NAME)))
|
||||
$(eval $(call BuildPackage,$(PKG_NAME)))
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
PROG = xmppd
|
||||
LIB = libxmpp.so
|
||||
|
||||
PROG_OBJS = xmpp.o xuci.o cmd.o log.o
|
||||
LIB_OBJS = datamodel.o
|
||||
|
||||
PROG_CFLAGS = $(CFLAGS) -Wall -Werror -fPIC
|
||||
PROG_LDFLAGS = $(LDFLAGS) -luci -lubox -lstrophe
|
||||
LIB_LDFLAGS = $(LDFLAGS) -lbbf_api
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(PROG_CFLAGS) $(FPIC) -c -o $@ $<
|
||||
|
||||
all: $(PROG) $(LIB)
|
||||
|
||||
$(PROG): $(PROG_OBJS)
|
||||
$(CC) $(PROG_CFLAGS) -o $@ $^ $(PROG_LDFLAGS)
|
||||
|
||||
$(LIB): $(LIB_OBJS)
|
||||
$(CC) $(PROG_CFLAGS) $(LIB_LDFLAGS) -shared -o $@ $^
|
||||
|
||||
clean:
|
||||
rm -f *.o $(PROG) $(LIB)
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
|
||||
*
|
||||
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
static int pfds[2];
|
||||
|
||||
int xmpp_cmd(unsigned char dowait, int argc, ...)
|
||||
{
|
||||
int pid;
|
||||
va_list arg;
|
||||
|
||||
if (pipe(pfds) < 0)
|
||||
return -1;
|
||||
|
||||
if ((pid = fork()) == -1)
|
||||
return -1;
|
||||
|
||||
if (pid == 0) {
|
||||
/* child */
|
||||
int i;
|
||||
const char *argv[64];
|
||||
|
||||
va_start(arg, argc);
|
||||
for (i = 0; i < argc; i++)
|
||||
{
|
||||
argv[i] = va_arg(arg, char *);
|
||||
}
|
||||
argv[i] = NULL;
|
||||
va_end(arg);
|
||||
|
||||
close(pfds[0]);
|
||||
dup2(pfds[1], 1);
|
||||
close(pfds[1]);
|
||||
|
||||
execvp(argv[0], (char **) argv);
|
||||
exit(ESRCH);
|
||||
|
||||
} else if (pid < 0)
|
||||
return -1;
|
||||
|
||||
/* parent */
|
||||
close(pfds[1]);
|
||||
|
||||
if (dowait) {
|
||||
int status;
|
||||
while (wait(&status) != pid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xmpp_cmd_close(void)
|
||||
{
|
||||
close(pfds[0]);
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
|
||||
*
|
||||
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __XMPPCMD_H
|
||||
#define __XMPPCMD_H
|
||||
|
||||
int xmpp_cmd(unsigned char wait, int argc, ...);
|
||||
void xmpp_cmd_close(void);
|
||||
|
||||
#define XMPP_CMD(ARGC, args...) \
|
||||
do { \
|
||||
xmpp_cmd(1, ARGC, ##args); \
|
||||
xmpp_cmd_close(); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#endif //__XMPPCMD_H
|
||||
|
|
@ -1,646 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2020 iopsys Software Solutions AB
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1
|
||||
* as published by the Free Software Foundation
|
||||
*
|
||||
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
|
||||
*/
|
||||
|
||||
#include <libbbf_api/dmbbf.h>
|
||||
#include <libbbf_api/dmcommon.h>
|
||||
#include <libbbf_api/dmuci.h>
|
||||
#include <libbbf_api/dmubus.h>
|
||||
#include <libbbf_api/dmjson.h>
|
||||
|
||||
#include "datamodel.h"
|
||||
|
||||
/* ********** DynamicObj ********** */
|
||||
DM_MAP_OBJ tDynamicObj[] = {
|
||||
/* parentobj, nextobject, parameter */
|
||||
{"Device.", tDeviceXMPPObj, NULL},
|
||||
{0}
|
||||
};
|
||||
|
||||
static int add_xmpp_connection(char *refparam, struct dmctx *ctx, void *data, char **instance)
|
||||
{
|
||||
struct uci_section *xmpp_con = NULL, *xmpp_con_srv = NULL, *dmmap_xmpp = NULL;
|
||||
char id[16];
|
||||
|
||||
char *last_inst = get_last_instance_bbfdm("dmmap_xmpp", "connection", "con_inst");
|
||||
snprintf(id, sizeof(id), "%d", (last_inst) ? atoi(last_inst) + 1 : 1);
|
||||
|
||||
dmuci_add_section("xmpp", "connection", &xmpp_con);
|
||||
dmuci_set_value_by_section(xmpp_con, "xmpp_id", id);
|
||||
dmuci_set_value_by_section(xmpp_con, "enable", "0");
|
||||
dmuci_set_value_by_section(xmpp_con, "interval", "30");
|
||||
dmuci_set_value_by_section(xmpp_con, "attempt", "16");
|
||||
dmuci_set_value_by_section(xmpp_con, "serveralgorithm", "DNS-SRV");
|
||||
|
||||
dmuci_add_section("xmpp", "connection_server", &xmpp_con_srv);
|
||||
dmuci_set_value_by_section(xmpp_con_srv, "con_id", id);
|
||||
dmuci_set_value_by_section(xmpp_con_srv, "enable", "0");
|
||||
dmuci_set_value_by_section(xmpp_con_srv, "port", "5222");
|
||||
|
||||
dmuci_add_section_bbfdm("dmmap_xmpp", "connection_server", &dmmap_xmpp);
|
||||
dmuci_set_value_by_section(dmmap_xmpp, "section_name", section_name(xmpp_con_srv));
|
||||
dmuci_set_value_by_section(dmmap_xmpp, "con_srv_inst", "1");
|
||||
|
||||
dmuci_add_section_bbfdm("dmmap_xmpp", "connection", &dmmap_xmpp);
|
||||
dmuci_set_value_by_section(dmmap_xmpp, "section_name", section_name(xmpp_con));
|
||||
*instance = update_instance(last_inst, 2, dmmap_xmpp, "con_inst");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int delete_xmpp_connection(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)
|
||||
{
|
||||
struct uci_section *s = NULL, *ss = NULL, *dmmap_section = NULL, *stmp = NULL;
|
||||
char *prev_con_id;
|
||||
int found = 0;
|
||||
|
||||
switch (del_action) {
|
||||
case DEL_INST:
|
||||
dmuci_get_value_by_section_string((struct uci_section *)data, "xmpp_id", &prev_con_id);
|
||||
uci_foreach_option_eq_safe("xmpp", "connection_server", "con_id", prev_con_id, stmp, s) {
|
||||
get_dmmap_section_of_config_section("dmmap_xmpp", "connection_server", section_name(s), &dmmap_section);
|
||||
dmuci_delete_by_section(dmmap_section, NULL, NULL);
|
||||
dmuci_delete_by_section(s, NULL, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
get_dmmap_section_of_config_section("dmmap_xmpp", "connection", section_name((struct uci_section *)data), &dmmap_section);
|
||||
dmuci_delete_by_section(dmmap_section, NULL, NULL);
|
||||
dmuci_delete_by_section((struct uci_section *)data, NULL, NULL);
|
||||
return 0;
|
||||
case DEL_ALL:
|
||||
uci_foreach_sections("xmpp", "connection", s) {
|
||||
if (found != 0) {
|
||||
get_dmmap_section_of_config_section("dmmap_xmpp", "connection", section_name(ss), &dmmap_section);
|
||||
dmuci_delete_by_section(dmmap_section, NULL, NULL);
|
||||
dmuci_delete_by_section(ss, NULL, NULL);
|
||||
}
|
||||
ss = s;
|
||||
found++;
|
||||
}
|
||||
if (ss != NULL) {
|
||||
get_dmmap_section_of_config_section("dmmap_xmpp", "connection", section_name(ss), &dmmap_section);
|
||||
dmuci_delete_by_section(dmmap_section, NULL, NULL);
|
||||
dmuci_delete_by_section(ss, NULL, NULL);
|
||||
}
|
||||
|
||||
found = 0;
|
||||
uci_foreach_sections("xmpp", "connection_server", s) {
|
||||
if (found != 0) {
|
||||
get_dmmap_section_of_config_section("dmmap_xmpp", "connection_server", section_name(ss), &dmmap_section);
|
||||
dmuci_delete_by_section(dmmap_section, NULL, NULL);
|
||||
dmuci_delete_by_section(ss, NULL, NULL);
|
||||
}
|
||||
ss = s;
|
||||
found++;
|
||||
}
|
||||
if (ss != NULL) {
|
||||
get_dmmap_section_of_config_section("dmmap_xmpp", "connection_server", section_name(ss), &dmmap_section);
|
||||
dmuci_delete_by_section(dmmap_section, NULL, NULL);
|
||||
dmuci_delete_by_section(ss, NULL, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*#Device.XMPP.ConnectionNumberOfEntries!UCI:xmpp/xmpp_connection/*/
|
||||
static int get_xmpp_connection_nbr_entry(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
struct uci_section *s;
|
||||
int cnt = 0;
|
||||
|
||||
uci_foreach_sections("xmpp", "connection", s) {
|
||||
cnt++;
|
||||
}
|
||||
dmasprintf(value, "%d", cnt); // MEM WILL BE FREED IN DMMEMCLEAN
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_xmpp_connection_supported_server_connect_algorithms(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
*value = "DNS-SRV,ServerTable";
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*#Device.XMPP.Connection.{i}.Enable!UCI:xmpp/xmpp_connection,@i-1/enable*/
|
||||
static int get_connection_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
*value = dmuci_get_value_by_section_fallback_def((struct uci_section *)data, "enable", "1");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_connection_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||
{
|
||||
bool b;
|
||||
|
||||
switch (action) {
|
||||
case VALUECHECK:
|
||||
if (dm_validate_boolean(value))
|
||||
return FAULT_9007;
|
||||
return 0;
|
||||
case VALUESET:
|
||||
string_to_bool(value, &b);
|
||||
dmuci_set_value_by_section((struct uci_section *)data, "enable", b ? "1" : "0");
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*#Device.XMPP.Connection.{i}.Alias!UCI:dmmap_xmpp/connection,@i-1/con_alias*/
|
||||
static int get_xmpp_connection_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
struct uci_section *dmmap_section = NULL;
|
||||
|
||||
get_dmmap_section_of_config_section("dmmap_xmpp", "connection", section_name((struct uci_section *)data), &dmmap_section);
|
||||
dmuci_get_value_by_section_string(dmmap_section, "con_alias", value);
|
||||
if ((*value)[0] == '\0')
|
||||
dmasprintf(value, "cpe-%s", instance);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_xmpp_connection_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||
{
|
||||
struct uci_section *dmmap_section = NULL;
|
||||
|
||||
switch (action) {
|
||||
case VALUECHECK:
|
||||
if (dm_validate_string(value, -1, 64, NULL, NULL))
|
||||
return FAULT_9007;
|
||||
return 0;
|
||||
case VALUESET:
|
||||
get_dmmap_section_of_config_section("dmmap_xmpp", "connection", section_name((struct uci_section *)data), &dmmap_section);
|
||||
dmuci_set_value_by_section(dmmap_section, "con_alias", value);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*#Device.XMPP.Connection.{i}.Username!UCI:xmpp/xmpp_connection,@i-1/username*/
|
||||
static int get_xmpp_connection_username(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
dmuci_get_value_by_section_string((struct uci_section *)data, "username", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_xmpp_connection_username(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||
{
|
||||
switch (action) {
|
||||
case VALUECHECK:
|
||||
if (dm_validate_string(value, -1, 256, NULL, NULL))
|
||||
return FAULT_9007;
|
||||
return 0;
|
||||
case VALUESET:
|
||||
dmuci_set_value_by_section((struct uci_section *)data, "username", value);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*#Device.XMPP.Connection.{i}.Password!UCI:xmpp/xmpp_connection,@i-1/password*/
|
||||
static int get_xmpp_connection_password(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
*value = "";
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_xmpp_connection_password(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||
{
|
||||
switch (action) {
|
||||
case VALUECHECK:
|
||||
if (dm_validate_string(value, -1, 256, NULL, NULL))
|
||||
return FAULT_9007;
|
||||
return 0;
|
||||
case VALUESET:
|
||||
dmuci_set_value_by_section((struct uci_section *)data, "password", value);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*#Device.XMPP.Connection.{i}.Domain!UCI:xmpp/xmpp_connection,@i-1/domain*/
|
||||
static int get_xmpp_connection_domain(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
dmuci_get_value_by_section_string((struct uci_section *)data, "domain", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_xmpp_connection_domain(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||
{
|
||||
switch (action) {
|
||||
case VALUECHECK:
|
||||
if (dm_validate_string(value, -1, 64, NULL, NULL))
|
||||
return FAULT_9007;
|
||||
return 0;
|
||||
case VALUESET:
|
||||
dmuci_set_value_by_section((struct uci_section *)data, "domain", value);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*#Device.XMPP.Connection.{i}.Resource!UCI:xmpp/xmpp_connection,@i-1/resource*/
|
||||
static int get_xmpp_connection_resource(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
dmuci_get_value_by_section_string((struct uci_section *)data, "resource", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_xmpp_connection_resource(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||
{
|
||||
switch (action) {
|
||||
case VALUECHECK:
|
||||
if (dm_validate_string(value, -1, 64, NULL, NULL))
|
||||
return FAULT_9007;
|
||||
return 0;
|
||||
case VALUESET:
|
||||
dmuci_set_value_by_section((struct uci_section *)data, "resource", value);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*#Device.XMPP.Connection.{i}.ServerConnectAlgorithm!UCI:xmpp/xmpp_connection,@i-1/serveralgorithm*/
|
||||
static int get_xmpp_connection_server_connect_algorithm(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
dmuci_get_value_by_section_string((struct uci_section *)data, "serveralgorithm", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_xmpp_connection_server_connect_algorithm(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||
{
|
||||
switch (action) {
|
||||
case VALUECHECK:
|
||||
if (dm_validate_string(value, -1, -1, ServerConnectAlgorithm, NULL))
|
||||
return FAULT_9007;
|
||||
return 0;
|
||||
case VALUESET:
|
||||
dmuci_set_value_by_section((struct uci_section *)data, "serveralgorithm", value);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*#Device.XMPP.Connection.{i}.KeepAliveInterval!UCI:xmpp/xmpp_connection,@i-1/interval*/
|
||||
static int get_xmpp_connection_keepalive_interval(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
*value = dmuci_get_value_by_section_fallback_def((struct uci_section *)data, "interval", "-1");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_xmpp_connection_keepalive_interval(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||
{
|
||||
switch (action) {
|
||||
case VALUECHECK:
|
||||
if (dm_validate_long(value, RANGE_ARGS{{"-1",NULL}}, 1))
|
||||
return FAULT_9007;
|
||||
return 0;
|
||||
case VALUESET:
|
||||
dmuci_set_value_by_section((struct uci_section *)data, "interval", value);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*#Device.XMPP.Connection.{i}.ServerConnectAttempts!UCI:xmpp/xmpp_connection,@i-1/attempt*/
|
||||
static int get_xmpp_connection_server_attempts(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
*value = dmuci_get_value_by_section_fallback_def((struct uci_section *)data, "attempt", "16");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_xmpp_connection_server_attempts(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||
{
|
||||
switch (action) {
|
||||
case VALUECHECK:
|
||||
if (dm_validate_unsignedInt(value, RANGE_ARGS{{NULL,NULL}}, 1))
|
||||
return FAULT_9007;
|
||||
return 0;
|
||||
case VALUESET:
|
||||
dmuci_set_value_by_section((struct uci_section *)data, "attempt", value);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*#Device.XMPP.Connection.{i}.ServerRetryInitialInterval!UCI:xmpp/xmpp_connection,@i-1/initial_retry_interval*/
|
||||
static int get_xmpp_connection_retry_initial_interval(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
*value = dmuci_get_value_by_section_fallback_def((struct uci_section *)data, "initial_retry_interval", "60");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_xmpp_connection_retry_initial_interval(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||
{
|
||||
switch (action) {
|
||||
case VALUECHECK:
|
||||
if (dm_validate_unsignedInt(value, RANGE_ARGS{{"1","65535"}}, 1))
|
||||
return FAULT_9007;
|
||||
return 0;
|
||||
case VALUESET:
|
||||
dmuci_set_value_by_section((struct uci_section *)data, "initial_retry_interval", value);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*#Device.XMPP.Connection.{i}.ServerRetryIntervalMultiplier!UCI:xmpp/xmpp_connection,@i-1/retry_interval_multiplier*/
|
||||
static int get_xmpp_connection_retry_interval_multiplier(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
*value = dmuci_get_value_by_section_fallback_def((struct uci_section *)data, "retry_interval_multiplier", "2000");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_xmpp_connection_retry_interval_multiplier(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||
{
|
||||
switch (action) {
|
||||
case VALUECHECK:
|
||||
if (dm_validate_unsignedInt(value, RANGE_ARGS{{"1000","65535"}}, 1))
|
||||
return FAULT_9007;
|
||||
return 0;
|
||||
case VALUESET:
|
||||
dmuci_set_value_by_section((struct uci_section *)data, "retry_interval_multiplier", value);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*#Device.XMPP.Connection.{i}.ServerRetryMaxInterval!UCI:xmpp/xmpp_connection,@i-1/retry_max_interval*/
|
||||
static int get_xmpp_connection_retry_max_interval(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
*value = dmuci_get_value_by_section_fallback_def((struct uci_section *)data, "retry_max_interval", "30720");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_xmpp_connection_retry_max_interval(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||
{
|
||||
switch (action) {
|
||||
case VALUECHECK:
|
||||
if (dm_validate_unsignedInt(value, RANGE_ARGS{{"1",NULL}}, 1))
|
||||
return FAULT_9007;
|
||||
return 0;
|
||||
case VALUESET:
|
||||
dmuci_set_value_by_section((struct uci_section *)data, "retry_max_interval", value);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*#Device.XMPP.Connection.{i}.UseTLS!UCI:xmpp/xmpp_connection,@i-1/usetls*/
|
||||
static int get_xmpp_connection_server_usetls(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
*value = dmuci_get_value_by_section_fallback_def((struct uci_section *)data, "usetls", "1");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_xmpp_connection_server_usetls(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||
{
|
||||
bool b;
|
||||
|
||||
switch (action) {
|
||||
case VALUECHECK:
|
||||
if (dm_validate_boolean(value))
|
||||
return FAULT_9007;
|
||||
return 0;
|
||||
case VALUESET:
|
||||
string_to_bool(value, &b);
|
||||
dmuci_set_value_by_section((struct uci_section *)data, "usetls", b ? "1" : "0");
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_xmpp_connection_jabber_id(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
char *resource, *domain, *username;
|
||||
|
||||
dmuci_get_value_by_section_string((struct uci_section *)data, "resource", &resource);
|
||||
dmuci_get_value_by_section_string((struct uci_section *)data, "domain", &domain);
|
||||
dmuci_get_value_by_section_string((struct uci_section *)data, "username", &username);
|
||||
if (*resource != '\0' || *domain != '\0' || *username != '\0')
|
||||
dmasprintf(value, "%s@%s/%s", username, domain, resource);
|
||||
else
|
||||
*value = "";
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*#Device.XMPP.Connection.{i}.Status!UCI:xmpp/xmpp_connection,@i-1/enable*/
|
||||
static int get_xmpp_connection_status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
char *status;
|
||||
|
||||
dmuci_get_value_by_section_string((struct uci_section *)data, "enable", &status);
|
||||
*value = (strcmp(status, "1") == 0) ? "Enabled" : "Disabled";
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_xmpp_connection_server_number_of_entries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
*value = "1";
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*#Device.XMPP.Connection.{i}.Server.{i}.Enable!UCI:xmpp/xmpp_connection,@i-1/enable*/
|
||||
static int get_xmpp_connection_server_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
*value = dmuci_get_value_by_section_fallback_def((struct uci_section *)data, "enable", "1");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_xmpp_connection_server_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||
{
|
||||
bool b;
|
||||
|
||||
switch (action) {
|
||||
case VALUECHECK:
|
||||
if (dm_validate_boolean(value))
|
||||
return FAULT_9007;
|
||||
return 0;
|
||||
case VALUESET:
|
||||
string_to_bool(value, &b);
|
||||
dmuci_set_value_by_section((struct uci_section *)data, "enable", b ? "1" : "0");
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*#Device.XMPP.Connection.{i}.Server.{i}.Alias!UCI:dmmap_xmpp/connection_server,@i-1/con_srv_alias*/
|
||||
static int get_xmpp_connection_server_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
struct uci_section *dmmap_section = NULL;
|
||||
|
||||
get_dmmap_section_of_config_section("dmmap_xmpp", "connection_server", section_name((struct uci_section *)data), &dmmap_section);
|
||||
dmuci_get_value_by_section_string(dmmap_section, "con_srv_alias", value);
|
||||
if ((*value)[0] == '\0')
|
||||
dmasprintf(value, "cpe-%s", instance);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_xmpp_connection_server_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||
{
|
||||
struct uci_section *dmmap_section = NULL;
|
||||
|
||||
switch (action) {
|
||||
case VALUECHECK:
|
||||
if (dm_validate_string(value, -1, 64, NULL, NULL))
|
||||
return FAULT_9007;
|
||||
return 0;
|
||||
case VALUESET:
|
||||
get_dmmap_section_of_config_section("dmmap_xmpp", "connection_server", section_name((struct uci_section *)data), &dmmap_section);
|
||||
dmuci_set_value_by_section(dmmap_section, "con_srv_alias", value);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*#Device.XMPP.Connection.{i}.Server.{i}.ServerAddress!UCI:xmpp/xmpp_connection,@i-1/server_address*/
|
||||
static int get_xmpp_connection_server_server_address(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
dmuci_get_value_by_section_string((struct uci_section *)data, "server_address", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_xmpp_connection_server_server_address(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||
{
|
||||
switch (action) {
|
||||
case VALUECHECK:
|
||||
if (dm_validate_string(value, -1, 256, NULL, NULL))
|
||||
return FAULT_9007;
|
||||
return 0;
|
||||
case VALUESET:
|
||||
dmuci_set_value_by_section((struct uci_section *)data, "server_address", value);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*#Device.XMPP.Connection.{i}.Server.{i}.Port!UCI:xmpp/xmpp_connection,@i-1/port*/
|
||||
static int get_xmpp_connection_server_port(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||
{
|
||||
*value = dmuci_get_value_by_section_fallback_def((struct uci_section *)data, "port", "5222");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_xmpp_connection_server_port(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||
{
|
||||
switch (action) {
|
||||
case VALUECHECK:
|
||||
if (dm_validate_unsignedInt(value, RANGE_ARGS{{"0","65535"}}, 1))
|
||||
return FAULT_9007;
|
||||
return 0;
|
||||
case VALUESET:
|
||||
dmuci_set_value_by_section((struct uci_section *)data, "port", value);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* ENTRY METHOD
|
||||
**************************************************************/
|
||||
/*#Device.XMPP.Connection.{i}.!UCI:xmpp/xmpp_connection/dmmap_cwmp_xmpp*/
|
||||
static int browsexmpp_connectionInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
|
||||
{
|
||||
char *inst, *max_inst = NULL;
|
||||
struct dmmap_dup *p;
|
||||
LIST_HEAD(dup_list);
|
||||
|
||||
synchronize_specific_config_sections_with_dmmap("xmpp", "connection", "dmmap_xmpp", &dup_list);
|
||||
list_for_each_entry(p, &dup_list, list) {
|
||||
|
||||
inst = handle_update_instance(1, dmctx, &max_inst, update_instance_alias, 3,
|
||||
p->dmmap_section, "con_inst", "con_alias");
|
||||
|
||||
if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)p->config_section, inst) == DM_STOP)
|
||||
break;
|
||||
}
|
||||
free_dmmap_config_dup_list(&dup_list);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/*#Device.XMPP.Connection.{i}.!UCI:xmpp/xmpp_connection_server/dmmap_cwmp_xmpp*/
|
||||
static int browsexmpp_connection_serverInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
|
||||
{
|
||||
char *inst, *max_inst = NULL, *con_id;
|
||||
struct dmmap_dup *p;
|
||||
LIST_HEAD(dup_list);
|
||||
|
||||
dmuci_get_value_by_section_string((struct uci_section *)prev_data, "xmpp_id", &con_id);
|
||||
synchronize_specific_config_sections_with_dmmap_eq("xmpp", "connection_server", "dmmap_xmpp", "con_id", con_id, &dup_list);
|
||||
|
||||
list_for_each_entry(p, &dup_list, list) {
|
||||
|
||||
inst = handle_update_instance(2, dmctx, &max_inst, update_instance_alias, 3,
|
||||
p->dmmap_section, "con_srv_inst", "con_srv_alias");
|
||||
|
||||
if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)p->config_section, inst) == DM_STOP)
|
||||
break;
|
||||
}
|
||||
free_dmmap_config_dup_list(&dup_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* *** Device.XMPP. *** */
|
||||
DMOBJ tDeviceXMPPObj[] = {
|
||||
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys*/
|
||||
{"XMPP", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tXMPPObj, tXMPPParams, NULL, BBFDM_BOTH},
|
||||
{0}
|
||||
};
|
||||
|
||||
DMOBJ tXMPPObj[] = {
|
||||
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys*/
|
||||
{"Connection", &DMWRITE, add_xmpp_connection, delete_xmpp_connection, NULL, browsexmpp_connectionInst, NULL, NULL, tXMPPConnectionObj, tXMPPConnectionParams, NULL, BBFDM_BOTH, LIST_KEY{"Alias", "Username", "Domain", "Resource", NULL}},
|
||||
{0}
|
||||
};
|
||||
|
||||
DMLEAF tXMPPParams[] = {
|
||||
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/
|
||||
{"ConnectionNumberOfEntries", &DMREAD, DMT_UNINT, get_xmpp_connection_nbr_entry, NULL, BBFDM_BOTH},
|
||||
{"SupportedServerConnectAlgorithms", &DMREAD, DMT_STRING, get_xmpp_connection_supported_server_connect_algorithms, NULL, BBFDM_BOTH},
|
||||
{0}
|
||||
};
|
||||
|
||||
/* *** Device.XMPP.Connection.{i}. *** */
|
||||
DMOBJ tXMPPConnectionObj[] = {
|
||||
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys*/
|
||||
{"Server", &DMREAD, NULL, NULL, NULL, browsexmpp_connection_serverInst, NULL, NULL, NULL, tXMPPConnectionServerParams, NULL, BBFDM_BOTH, LIST_KEY{"Alias", "ServerAddress", "Port", NULL}},
|
||||
{0}
|
||||
};
|
||||
|
||||
DMLEAF tXMPPConnectionParams[] = {
|
||||
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/
|
||||
{"Enable", &DMWRITE, DMT_BOOL, get_connection_enable, set_connection_enable, BBFDM_BOTH},
|
||||
{"Alias", &DMWRITE, DMT_STRING, get_xmpp_connection_alias, set_xmpp_connection_alias, BBFDM_BOTH},
|
||||
{"Username", &DMWRITE, DMT_STRING, get_xmpp_connection_username, set_xmpp_connection_username, BBFDM_BOTH},
|
||||
{"Password", &DMWRITE, DMT_STRING, get_xmpp_connection_password, set_xmpp_connection_password, BBFDM_BOTH},
|
||||
{"Domain", &DMWRITE, DMT_STRING, get_xmpp_connection_domain, set_xmpp_connection_domain, BBFDM_BOTH},
|
||||
{"Resource", &DMWRITE, DMT_STRING, get_xmpp_connection_resource, set_xmpp_connection_resource, BBFDM_BOTH},
|
||||
{"ServerConnectAlgorithm", &DMWRITE, DMT_STRING, get_xmpp_connection_server_connect_algorithm, set_xmpp_connection_server_connect_algorithm, BBFDM_BOTH},
|
||||
{"KeepAliveInterval", &DMWRITE, DMT_LONG, get_xmpp_connection_keepalive_interval, set_xmpp_connection_keepalive_interval, BBFDM_BOTH},
|
||||
{"ServerConnectAttempts", &DMWRITE, DMT_UNINT, get_xmpp_connection_server_attempts, set_xmpp_connection_server_attempts, BBFDM_BOTH},
|
||||
{"ServerRetryInitialInterval", &DMWRITE, DMT_UNINT, get_xmpp_connection_retry_initial_interval, set_xmpp_connection_retry_initial_interval, BBFDM_BOTH},
|
||||
{"ServerRetryIntervalMultiplier", &DMWRITE, DMT_UNINT, get_xmpp_connection_retry_interval_multiplier, set_xmpp_connection_retry_interval_multiplier, BBFDM_BOTH},
|
||||
{"ServerRetryMaxInterval", &DMWRITE, DMT_UNINT, get_xmpp_connection_retry_max_interval, set_xmpp_connection_retry_max_interval, BBFDM_BOTH},
|
||||
{"UseTLS", &DMWRITE, DMT_BOOL, get_xmpp_connection_server_usetls, set_xmpp_connection_server_usetls, BBFDM_BOTH},
|
||||
{"JabberID", &DMREAD, DMT_STRING, get_xmpp_connection_jabber_id, NULL, BBFDM_BOTH},
|
||||
{"Status", &DMREAD, DMT_STRING, get_xmpp_connection_status, NULL, BBFDM_BOTH},
|
||||
{"ServerNumberOfEntries", &DMREAD, DMT_UNINT, get_xmpp_connection_server_number_of_entries, NULL, BBFDM_BOTH},
|
||||
{0}
|
||||
};
|
||||
|
||||
/* *** Device.XMPP.Connection.{i}.Server.{i}. *** */
|
||||
DMLEAF tXMPPConnectionServerParams[] = {
|
||||
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/
|
||||
{"Enable", &DMWRITE, DMT_BOOL, get_xmpp_connection_server_enable, set_xmpp_connection_server_enable, BBFDM_BOTH},
|
||||
{"Alias", &DMWRITE, DMT_STRING, get_xmpp_connection_server_alias, set_xmpp_connection_server_alias, BBFDM_BOTH},
|
||||
{"ServerAddress", &DMWRITE, DMT_STRING, get_xmpp_connection_server_server_address, set_xmpp_connection_server_server_address, BBFDM_BOTH},
|
||||
{"Port", &DMWRITE, DMT_UNINT, get_xmpp_connection_server_port, set_xmpp_connection_server_port, BBFDM_BOTH},
|
||||
{0}
|
||||
};
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2020 iopsys Software Solutions AB
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1
|
||||
* as published by the Free Software Foundation
|
||||
*
|
||||
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
|
||||
*/
|
||||
|
||||
#ifndef _XMPP_H_
|
||||
#define _XMPP_H_
|
||||
|
||||
extern DMOBJ tDeviceXMPPObj[];
|
||||
extern DMOBJ tXMPPObj[];
|
||||
extern DMLEAF tXMPPParams[];
|
||||
extern DMLEAF tXMPPConnectionParams[];
|
||||
extern DMOBJ tXMPPConnectionObj[];
|
||||
extern DMLEAF tXMPPConnectionServerParams[];
|
||||
|
||||
#endif //_XMPP_H_
|
||||
116
xmpp/src/log.c
116
xmpp/src/log.c
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
|
||||
*
|
||||
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <syslog.h>
|
||||
#include <strophe.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "xmpp.h"
|
||||
|
||||
static const int log_syslogmap[] = {
|
||||
[SCRIT] = LOG_CRIT,
|
||||
[SWARNING] = LOG_WARNING,
|
||||
[SNOTICE] = LOG_NOTICE,
|
||||
[SINFO] = LOG_INFO,
|
||||
[SDEBUG] = LOG_DEBUG
|
||||
};
|
||||
|
||||
static const char* log_str[] = {
|
||||
[SCRIT] = "CRITICAL",
|
||||
[SWARNING] = "WARNING",
|
||||
[SNOTICE] = "NOTICE",
|
||||
[SINFO] = "INFO",
|
||||
[SDEBUG] = "DEBUG"
|
||||
};
|
||||
|
||||
void xmpp_syslog(int priority, const char *format, ...)
|
||||
{
|
||||
va_list vl;
|
||||
|
||||
if (priority <= cur_xmpp_conf.xmpp_loglevel) {
|
||||
time_t t = time(NULL);
|
||||
struct tm tm = *localtime(&t);
|
||||
va_start(vl, format);
|
||||
printf("%d-%02d-%02d %02d:%02d:%02d [xmpp] %s - ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, log_str[priority]);
|
||||
vprintf(format, vl);
|
||||
va_end(vl);
|
||||
printf("\n");
|
||||
|
||||
openlog("xmpp", 0, LOG_DAEMON);
|
||||
va_start(vl, format);
|
||||
vsyslog(log_syslogmap[priority], format, vl);
|
||||
va_end(vl);
|
||||
closelog();
|
||||
}
|
||||
}
|
||||
|
||||
void xmpp_syslog_handler(void * const userdata,
|
||||
const xmpp_log_level_t level,
|
||||
const char * const area,
|
||||
const char * const msg)
|
||||
{
|
||||
int priority = SDEBUG;
|
||||
xmpp_log_level_t filter_level = *(xmpp_log_level_t *)userdata;
|
||||
|
||||
if (level >= filter_level) {
|
||||
switch (level) {
|
||||
case XMPP_LEVEL_ERROR:
|
||||
priority = SCRIT;
|
||||
break;
|
||||
case XMPP_LEVEL_WARN:
|
||||
priority = SWARNING;
|
||||
break;
|
||||
case XMPP_LEVEL_INFO:
|
||||
priority = SINFO;
|
||||
break;
|
||||
case XMPP_LEVEL_DEBUG:
|
||||
priority = SDEBUG;
|
||||
break;
|
||||
}
|
||||
|
||||
xmpp_syslog(priority, "%s %s", area, msg);
|
||||
}
|
||||
}
|
||||
|
||||
xmpp_log_level_t xmpp_log_get_level(int conf_loglevel)
|
||||
{
|
||||
xmpp_log_level_t xmpp_level = XMPP_LEVEL_DEBUG;
|
||||
|
||||
switch (conf_loglevel) {
|
||||
case SCRIT:
|
||||
xmpp_level = XMPP_LEVEL_ERROR;
|
||||
break;
|
||||
case SWARNING:
|
||||
xmpp_level = XMPP_LEVEL_WARN;
|
||||
break;
|
||||
case SINFO:
|
||||
case SNOTICE:
|
||||
xmpp_level = XMPP_LEVEL_INFO;
|
||||
break;
|
||||
case SDEBUG:
|
||||
xmpp_level = XMPP_LEVEL_DEBUG;
|
||||
break;
|
||||
}
|
||||
|
||||
return xmpp_level;
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
|
||||
*
|
||||
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _XMPPLOG_H_
|
||||
#define _XMPPLOG_H_
|
||||
|
||||
#define DEFAULT_LOGLEVEL SINFO
|
||||
|
||||
enum xmpp_log_level_enum {
|
||||
SCRIT,
|
||||
SWARNING,
|
||||
SNOTICE,
|
||||
SINFO,
|
||||
SDEBUG,
|
||||
__MAX_SLOG
|
||||
};
|
||||
|
||||
void xmpp_syslog(int priority, const char *format, ...);
|
||||
void xmpp_syslog_handler(void * const userdata,
|
||||
const xmpp_log_level_t level,
|
||||
const char * const area,
|
||||
const char * const msg);
|
||||
xmpp_log_level_t xmpp_log_get_level(int conf_loglevel);
|
||||
|
||||
#endif /* _XMPPLOG_H_ */
|
||||
519
xmpp/src/xmpp.c
519
xmpp/src/xmpp.c
|
|
@ -1,519 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
|
||||
*
|
||||
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
|
||||
*
|
||||
* This program is FREE software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the FREE Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the FREE Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strophe.h>
|
||||
|
||||
#include "xmpp.h"
|
||||
#include "cmd.h"
|
||||
#include "log.h"
|
||||
#include "xuci.h"
|
||||
|
||||
struct xmpp_config cur_xmpp_conf = {0};
|
||||
struct xmpp_connection cur_xmpp_con = {0};
|
||||
|
||||
static void xmpp_connecting(void);
|
||||
static void xmpp_exit(xmpp_ctx_t *ctx, xmpp_conn_t *conn);
|
||||
static void xmpp_con_exit(void);
|
||||
|
||||
static int send_stanza_cr_response(xmpp_conn_t *const conn, xmpp_stanza_t *const stanza, void * const userdata)
|
||||
{
|
||||
xmpp_stanza_t *reply = xmpp_stanza_new((xmpp_ctx_t *)userdata);
|
||||
if (!reply) {
|
||||
xmpp_syslog(SCRIT,"XMPP CR response Error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
xmpp_stanza_set_name(reply, "iq");
|
||||
xmpp_stanza_set_type(reply, "result");
|
||||
xmpp_stanza_set_attribute(reply, "from", xmpp_stanza_get_attribute(stanza, "to"));
|
||||
xmpp_stanza_set_attribute(reply, "id", xmpp_stanza_get_attribute(stanza, "id"));
|
||||
xmpp_stanza_set_attribute(reply, "to", xmpp_stanza_get_attribute(stanza, "from"));
|
||||
xmpp_send(conn, reply);
|
||||
xmpp_stanza_release(reply);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_stanza_cr_error(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata, int xmpp_error)
|
||||
{
|
||||
xmpp_ctx_t *ctx = (xmpp_ctx_t*)userdata;
|
||||
char *username = NULL, *password = NULL;
|
||||
|
||||
xmpp_stanza_t *cr_stanza = xmpp_stanza_new(ctx);
|
||||
if (!cr_stanza) {
|
||||
xmpp_syslog(SCRIT,"XMPP CR response Error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
xmpp_stanza_set_name(cr_stanza, "iq");
|
||||
xmpp_stanza_set_type(cr_stanza, "error");
|
||||
xmpp_stanza_set_attribute(cr_stanza, "id", xmpp_stanza_get_attribute(stanza, "id"));
|
||||
xmpp_stanza_set_attribute(cr_stanza, "to", xmpp_stanza_get_attribute(stanza, "from"));
|
||||
xmpp_stanza_set_attribute(cr_stanza, "from", xmpp_stanza_get_attribute(stanza, "to"));
|
||||
|
||||
// Connection Request Message
|
||||
xmpp_stanza_t *stanza_cr = xmpp_stanza_get_child_by_name(stanza, "connectionRequest");
|
||||
if (stanza_cr) {
|
||||
// Username
|
||||
xmpp_stanza_t *stanza_username = xmpp_stanza_get_child_by_name(stanza_cr, "username");
|
||||
if (stanza_username)
|
||||
username = xmpp_stanza_get_text(stanza_username);
|
||||
|
||||
//Password
|
||||
xmpp_stanza_t *stanza_password = xmpp_stanza_get_next(stanza_username);
|
||||
if (strcmp(xmpp_stanza_get_name(stanza_password), "password") == 0)
|
||||
password = xmpp_stanza_get_text(stanza_password);
|
||||
}
|
||||
|
||||
xmpp_stanza_t *stanza_cr_msg = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(stanza_cr_msg, "connectionRequest");
|
||||
xmpp_stanza_set_ns(stanza_cr_msg, XMPP_CR_NS);
|
||||
|
||||
xmpp_stanza_t *stanza_username_msg = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(stanza_username_msg, "username");
|
||||
|
||||
xmpp_stanza_t *username_msg = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_text(username_msg, username);
|
||||
xmpp_stanza_add_child(stanza_username_msg, username_msg);
|
||||
xmpp_stanza_release(username_msg);
|
||||
|
||||
xmpp_stanza_add_child(stanza_cr_msg, stanza_username_msg);
|
||||
xmpp_stanza_release(stanza_username_msg);
|
||||
|
||||
xmpp_stanza_t *stanza_password_msg = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(stanza_password_msg, "password");
|
||||
|
||||
xmpp_stanza_t *password_msg = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_text(password_msg, password);
|
||||
xmpp_stanza_add_child(stanza_password_msg, password_msg);
|
||||
xmpp_stanza_release(password_msg);
|
||||
|
||||
xmpp_stanza_add_child(stanza_cr_msg, stanza_password_msg);
|
||||
xmpp_stanza_release(stanza_password_msg);
|
||||
|
||||
xmpp_stanza_add_child(cr_stanza, stanza_cr_msg);
|
||||
xmpp_stanza_release(stanza_cr_msg);
|
||||
|
||||
xmpp_stanza_t *stanza_error = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(stanza_error, "error");
|
||||
if (xmpp_error == XMPP_SERVICE_UNAVAILABLE)
|
||||
xmpp_stanza_set_attribute(stanza_error, "code", "503");
|
||||
|
||||
xmpp_stanza_set_type(stanza_error, "cancel");
|
||||
xmpp_stanza_t *stanza_service = xmpp_stanza_new(ctx);
|
||||
if (xmpp_error == XMPP_SERVICE_UNAVAILABLE)
|
||||
xmpp_stanza_set_name(stanza_service, "service-unavailable");
|
||||
else if (xmpp_error == XMPP_NOT_AUTHORIZED)
|
||||
xmpp_stanza_set_name(stanza_service, "not-autorized");
|
||||
|
||||
xmpp_stanza_set_attribute(stanza_service, "xmlns", XMPP_ERROR_NS);
|
||||
xmpp_stanza_add_child(stanza_error, stanza_service);
|
||||
xmpp_stanza_release(stanza_service);
|
||||
|
||||
xmpp_stanza_add_child(cr_stanza, stanza_error);
|
||||
xmpp_stanza_release(stanza_error);
|
||||
|
||||
xmpp_send(conn, cr_stanza);
|
||||
xmpp_stanza_release(cr_stanza);
|
||||
|
||||
// Free allocated memory
|
||||
FREE(username);
|
||||
FREE(password);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool check_xmpp_jid_authorized(const char *from)
|
||||
{
|
||||
// XMPP config : allowed jabber id is empty
|
||||
if (cur_xmpp_conf.xmpp_allowed_jid == NULL || cur_xmpp_conf.xmpp_allowed_jid[0] == '\0') {
|
||||
xmpp_syslog(SDEBUG,"xmpp connection request handler : allowed jid is empty");
|
||||
return true;
|
||||
}
|
||||
|
||||
// XMPP config : allowed jabber id is not empty
|
||||
char *spch = NULL;
|
||||
|
||||
xmpp_syslog(SDEBUG,"xmpp connection request handler : check each jabber id");
|
||||
char *allowed_jid = strdup(cur_xmpp_conf.xmpp_allowed_jid);
|
||||
char *pch = strtok_r(allowed_jid, ",", &spch);
|
||||
while (pch != NULL) {
|
||||
if (strncmp(pch, from, strlen(pch)) == 0) {
|
||||
FREE(allowed_jid);
|
||||
xmpp_syslog(SDEBUG,"xmpp connection request handler : jabber id is authorized");
|
||||
return true;
|
||||
}
|
||||
pch = strtok_r(NULL, ",", &spch);
|
||||
}
|
||||
FREE(allowed_jid);
|
||||
|
||||
xmpp_syslog(SDEBUG,"xmpp connection request handler : jabber id is not authorized");
|
||||
return false;
|
||||
}
|
||||
|
||||
static int cr_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata)
|
||||
{
|
||||
bool valid_ns = true, auth_status = false, service_available = false;
|
||||
|
||||
if (xmpp_stanza_get_child_by_name(stanza, "connectionRequest")) {
|
||||
const char *from = (char *)xmpp_stanza_get_attribute(stanza, "from");
|
||||
|
||||
if (!check_xmpp_jid_authorized(from)) {
|
||||
service_available = false;
|
||||
xmpp_syslog(SDEBUG,"xmpp connection request handler not authorized by allowed jid");
|
||||
goto xmpp_end;
|
||||
}
|
||||
} else {
|
||||
xmpp_syslog(SDEBUG,"xmpp connection request handler does not contain an iq type");
|
||||
return 1;
|
||||
}
|
||||
|
||||
xmpp_stanza_t *stanza_cr = xmpp_stanza_get_child_by_name(stanza, "connectionRequest");
|
||||
if (stanza_cr) {
|
||||
service_available = true;
|
||||
char *name_space = (char *)xmpp_stanza_get_attribute(stanza_cr, "xmlns");
|
||||
if (strcmp(name_space, XMPP_CR_NS) != 0) {
|
||||
valid_ns = false;
|
||||
goto xmpp_end; //send error response
|
||||
}
|
||||
|
||||
xmpp_stanza_t *mech = xmpp_stanza_get_child_by_name(stanza_cr, "username");
|
||||
if (mech) {
|
||||
char *text = xmpp_stanza_get_text(mech);
|
||||
xmpp_uci_init();
|
||||
const char *username = xmpp_uci_get_value("cwmp", "cpe", "userid");
|
||||
if (strcmp(text, username) == 0) {
|
||||
FREE(text);
|
||||
mech = xmpp_stanza_get_next(mech);
|
||||
if (strcmp(xmpp_stanza_get_name(mech), "password") == 0) {
|
||||
text = xmpp_stanza_get_text(mech);
|
||||
const char *password = xmpp_uci_get_value("cwmp", "cpe", "passwd");
|
||||
auth_status = (strcmp(text, password) == 0) ? true : false;
|
||||
}
|
||||
}
|
||||
xmpp_uci_fini();
|
||||
FREE(text);
|
||||
}
|
||||
} else {
|
||||
service_available = false;
|
||||
goto xmpp_end; //send error response
|
||||
}
|
||||
|
||||
xmpp_end:
|
||||
if (!valid_ns) {
|
||||
|
||||
xmpp_syslog(SINFO, "XMPP Invalid Name space");
|
||||
send_stanza_cr_error(conn, stanza, userdata, XMPP_SERVICE_UNAVAILABLE);
|
||||
|
||||
} else if (!service_available) {
|
||||
|
||||
xmpp_syslog(SINFO, "XMPP Service Unavailable");
|
||||
send_stanza_cr_error(conn, stanza, userdata, XMPP_SERVICE_UNAVAILABLE);
|
||||
|
||||
} else if (!auth_status) {
|
||||
|
||||
xmpp_syslog(SINFO, "XMPP Not Authorized");
|
||||
send_stanza_cr_error(conn, stanza, userdata, XMPP_NOT_AUTHORIZED);
|
||||
|
||||
} else {
|
||||
|
||||
xmpp_syslog(SINFO, "XMPP Authorized");
|
||||
send_stanza_cr_response(conn, stanza, userdata);
|
||||
XMPP_CMD(7, "ubus", "-t", "3", "call", "tr069", "inform", "{\"event\" : \"6 connection request\"}");
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ping_keepalive_handler(xmpp_conn_t * const conn, void * const userdata)
|
||||
{
|
||||
xmpp_stanza_t *ping_ka, *ping;
|
||||
xmpp_ctx_t *ctx = (xmpp_ctx_t*)userdata;
|
||||
char jid[512] = {0};
|
||||
|
||||
xmpp_syslog(SDEBUG, "XMPP PING OF KEEPALIVE ");
|
||||
|
||||
snprintf(jid, sizeof(jid), "%s@%s/%s", cur_xmpp_con.username, cur_xmpp_con.domain, cur_xmpp_con.resource);
|
||||
|
||||
ping_ka = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(ping_ka, "iq");
|
||||
xmpp_stanza_set_type(ping_ka, "get");
|
||||
xmpp_stanza_set_id(ping_ka, "s2c1");
|
||||
xmpp_stanza_set_attribute(ping_ka, "from", jid);
|
||||
xmpp_stanza_set_attribute(ping_ka, "to", cur_xmpp_con.domain);
|
||||
|
||||
ping = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(ping, "ping");
|
||||
xmpp_stanza_set_attribute(ping, "xmlns", "urn:xmpp:ping");
|
||||
xmpp_stanza_add_child(ping_ka, ping);
|
||||
xmpp_stanza_release(ping);
|
||||
xmpp_send(conn, ping_ka);
|
||||
xmpp_stanza_release(ping_ka);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
|
||||
const int error, xmpp_stream_error_t * const stream_error,
|
||||
void * const userdata)
|
||||
{
|
||||
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
|
||||
static int attempt = 0;
|
||||
|
||||
if (status == XMPP_CONN_CONNECT) {
|
||||
xmpp_syslog(SINFO,"XMPP Connection Established");
|
||||
attempt = 0;
|
||||
|
||||
xmpp_handler_add(conn, cr_handler, NULL, "iq", NULL, ctx);
|
||||
xmpp_timed_handler_add(conn, ping_keepalive_handler, cur_xmpp_con.keepalive_interval * 1000, userdata);
|
||||
|
||||
xmpp_stanza_t *pres = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(pres, "presence");
|
||||
xmpp_send(conn, pres);
|
||||
xmpp_stanza_release(pres);
|
||||
|
||||
xmpp_conn_set_keepalive(conn, 30, cur_xmpp_con.keepalive_interval);
|
||||
} else {
|
||||
xmpp_syslog(SINFO,"XMPP Connection Lost");
|
||||
xmpp_exit(ctx, conn);
|
||||
|
||||
xmpp_syslog(SINFO,"XMPP Connection Retry");
|
||||
srand(time(NULL));
|
||||
|
||||
if (attempt == 0 && cur_xmpp_con.connect_attempt != 0) {
|
||||
|
||||
if (cur_xmpp_con.retry_initial_interval != 0)
|
||||
sleep(rand()%cur_xmpp_con.retry_initial_interval);
|
||||
|
||||
} else if(attempt > cur_xmpp_con.connect_attempt) {
|
||||
|
||||
xmpp_syslog(SINFO,"XMPP Connection Aborted");
|
||||
xmpp_exit(ctx, conn);
|
||||
xmpp_con_exit();
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
} else if( attempt >= 1 && cur_xmpp_con.connect_attempt != 0 ) {
|
||||
|
||||
int delay = cur_xmpp_con.retry_initial_interval * (cur_xmpp_con.retry_interval_multiplier/1000) * (attempt -1);
|
||||
if (delay > cur_xmpp_con.retry_max_interval)
|
||||
sleep(cur_xmpp_con.retry_max_interval);
|
||||
else
|
||||
sleep(delay);
|
||||
|
||||
} else
|
||||
sleep(DEFAULT_XMPP_RECONNECTION_RETRY);
|
||||
|
||||
attempt += 1;
|
||||
xmpp_connecting();
|
||||
}
|
||||
}
|
||||
|
||||
static void xmpp_connecting(void)
|
||||
{
|
||||
xmpp_log_t log_xmpp;
|
||||
char jid[512] = {0};
|
||||
static int attempt = 0;
|
||||
int connected = 0;
|
||||
long flags = 0;
|
||||
|
||||
xmpp_initialize();
|
||||
int xmpp_mesode_log_level = xmpp_log_get_level(cur_xmpp_conf.xmpp_loglevel);
|
||||
log_xmpp.handler = &xmpp_syslog_handler;
|
||||
log_xmpp.userdata = &(xmpp_mesode_log_level);
|
||||
xmpp_ctx_t *ctx = xmpp_ctx_new(NULL, &log_xmpp);
|
||||
xmpp_conn_t *conn = xmpp_conn_new(ctx);
|
||||
|
||||
if(cur_xmpp_con.usetls)
|
||||
flags |= XMPP_CONN_FLAG_MANDATORY_TLS; /* Set flag XMPP_CONN_FLAG_MANDATORY_TLS to oblige the verification of tls */
|
||||
else
|
||||
flags |= XMPP_CONN_FLAG_TRUST_TLS; /* Set flag XMPP_CONN_FLAG_TRUST_TLS to ignore result of the verification */
|
||||
xmpp_conn_set_flags(conn, flags);
|
||||
|
||||
snprintf(jid, sizeof(jid), "%s@%s/%s", cur_xmpp_con.username, cur_xmpp_con.domain, cur_xmpp_con.resource);
|
||||
|
||||
xmpp_conn_set_jid(conn, jid);
|
||||
xmpp_conn_set_pass(conn, cur_xmpp_con.password);
|
||||
|
||||
/* initiate connection */
|
||||
if( strcmp(cur_xmpp_con.serveralgorithm,"DNS-SRV") == 0)
|
||||
connected = xmpp_connect_client(conn, NULL, 0, conn_handler, ctx);
|
||||
else
|
||||
connected = xmpp_connect_client(conn, cur_xmpp_con.serveraddress[0] ? cur_xmpp_con.serveraddress : NULL,
|
||||
cur_xmpp_con.port, conn_handler, ctx);
|
||||
|
||||
if (connected < 0 ) {
|
||||
xmpp_exit(ctx, conn);
|
||||
xmpp_syslog(SINFO,"XMPP Connection Retry");
|
||||
srand(time(NULL));
|
||||
if (attempt == 0 && cur_xmpp_con.connect_attempt != 0) {
|
||||
if (cur_xmpp_con.retry_initial_interval != 0)
|
||||
sleep(rand()%cur_xmpp_con.retry_initial_interval);
|
||||
} else if (attempt > cur_xmpp_con.connect_attempt) {
|
||||
xmpp_syslog(SINFO,"XMPP Connection Aborted");
|
||||
xmpp_exit(ctx, conn);
|
||||
xmpp_con_exit();
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (attempt >= 1 && cur_xmpp_con.connect_attempt != 0) {
|
||||
int delay = cur_xmpp_con.retry_initial_interval * (cur_xmpp_con.retry_interval_multiplier/1000) * (attempt -1);
|
||||
if (delay > cur_xmpp_con.retry_max_interval)
|
||||
sleep(cur_xmpp_con.retry_max_interval);
|
||||
else
|
||||
sleep(delay);
|
||||
} else
|
||||
sleep(DEFAULT_XMPP_RECONNECTION_RETRY);
|
||||
attempt += 1;
|
||||
xmpp_connecting();
|
||||
} else {
|
||||
attempt = 0;
|
||||
xmpp_syslog(SDEBUG,"XMPP Handle Connection");
|
||||
xmpp_run(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static void xmpp_exit(xmpp_ctx_t *ctx, xmpp_conn_t *conn)
|
||||
{
|
||||
xmpp_stop(ctx);
|
||||
xmpp_conn_release(conn);
|
||||
xmpp_ctx_free(ctx);
|
||||
xmpp_shutdown();
|
||||
}
|
||||
|
||||
static void xmpp_con_exit(void)
|
||||
{
|
||||
FREE(cur_xmpp_con.username);
|
||||
FREE(cur_xmpp_con.password);
|
||||
FREE(cur_xmpp_con.domain);
|
||||
FREE(cur_xmpp_con.resource);
|
||||
FREE(cur_xmpp_con.serveraddress);
|
||||
FREE(cur_xmpp_con.serveralgorithm);
|
||||
FREE(cur_xmpp_conf.xmpp_allowed_jid);
|
||||
}
|
||||
|
||||
static void xmpp_global_conf(void)
|
||||
{
|
||||
xmpp_uci_init();
|
||||
|
||||
// XMPP Log Level
|
||||
const char *loglevel = xmpp_uci_get_value("xmpp", "xmpp", "loglevel");
|
||||
if (loglevel != NULL && *loglevel != '\0')
|
||||
cur_xmpp_conf.xmpp_loglevel = atoi(loglevel);
|
||||
else
|
||||
cur_xmpp_conf.xmpp_loglevel = DEFAULT_LOGLEVEL;
|
||||
xmpp_syslog(SDEBUG,"Log Level of XMPP connection is :%d", cur_xmpp_conf.xmpp_loglevel);
|
||||
|
||||
// XMPP Allowed Jabber id
|
||||
const char *allowed_jid = xmpp_uci_get_value("xmpp", "xmpp", "allowed_jid");
|
||||
if (allowed_jid != NULL && *allowed_jid != '\0') {
|
||||
cur_xmpp_conf.xmpp_allowed_jid = strdup(allowed_jid);
|
||||
xmpp_syslog(SDEBUG,"XMPP connection allowed jaber id :%s", cur_xmpp_conf.xmpp_allowed_jid);
|
||||
} else {
|
||||
cur_xmpp_conf.xmpp_allowed_jid = strdup("");
|
||||
xmpp_syslog(SDEBUG,"XMPP connection allowed jaber id is empty");
|
||||
}
|
||||
|
||||
xmpp_uci_fini();
|
||||
}
|
||||
|
||||
static const char *get_connection_config(const char *option, const char *identifier)
|
||||
{
|
||||
struct uci_section *s;
|
||||
|
||||
xmpp_uci_foreach_section("xmpp", "connection", s) {
|
||||
const char *xmpp_id = xmpp_uci_get_value_bysection(s, "xmpp_id");
|
||||
if (strcmp(xmpp_id, identifier) == 0)
|
||||
return xmpp_uci_get_value_bysection(s, option);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static const char *get_connection_server_config(const char *option, const char *identifier)
|
||||
{
|
||||
struct uci_section *s;
|
||||
|
||||
xmpp_uci_foreach_section("xmpp", "connection_server", s) {
|
||||
const char *con_id = xmpp_uci_get_value_bysection(s, "con_id");
|
||||
if (strcmp(con_id, identifier) == 0)
|
||||
return xmpp_uci_get_value_bysection(s, option);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static void xmpp_con_init(void)
|
||||
{
|
||||
xmpp_uci_init();
|
||||
|
||||
const char *identifier = xmpp_uci_get_value("xmpp", "xmpp", "id");
|
||||
|
||||
cur_xmpp_con.username = strdup(get_connection_config("username", identifier));
|
||||
cur_xmpp_con.password = strdup(get_connection_config("password", identifier));
|
||||
cur_xmpp_con.domain = strdup(get_connection_config("domain", identifier));
|
||||
cur_xmpp_con.resource = strdup(get_connection_config("resource", identifier));
|
||||
cur_xmpp_con.usetls = atoi(get_connection_config("usetls", identifier));
|
||||
cur_xmpp_con.serveralgorithm = strdup(get_connection_config("serveralgorithm", identifier));
|
||||
cur_xmpp_con.serveraddress = strdup(get_connection_server_config("server_address", identifier));
|
||||
cur_xmpp_con.port = atoi(get_connection_server_config("port", identifier));
|
||||
cur_xmpp_con.keepalive_interval = atoi(get_connection_config("interval", identifier));
|
||||
|
||||
cur_xmpp_con.connect_attempt = atoi(get_connection_config("attempt", identifier));
|
||||
if (cur_xmpp_con.connect_attempt) {
|
||||
cur_xmpp_con.retry_initial_interval = atoi(get_connection_config("initial_retry_interval", identifier));
|
||||
cur_xmpp_con.retry_initial_interval = (cur_xmpp_con.retry_initial_interval) ? cur_xmpp_con.retry_initial_interval : DEFAULT_RETRY_INITIAL_INTERVAL;
|
||||
cur_xmpp_con.retry_interval_multiplier = atoi(get_connection_config("retry_interval_multiplier", identifier));
|
||||
cur_xmpp_con.retry_interval_multiplier = (cur_xmpp_con.retry_interval_multiplier) ? cur_xmpp_con.retry_interval_multiplier : DEFAULT_RETRY_INTERVAL_MULTIPLIER;
|
||||
cur_xmpp_con.retry_max_interval = atoi(get_connection_config("retry_max_interval", identifier));
|
||||
cur_xmpp_con.retry_max_interval = (cur_xmpp_con.retry_max_interval) ? cur_xmpp_con.retry_max_interval : DEFAULT_RETRY_MAX_INTERVAL;
|
||||
}
|
||||
|
||||
xmpp_syslog(SDEBUG,"XMPP Connection id: %s", identifier);
|
||||
xmpp_syslog(SDEBUG,"XMPP username: %s", cur_xmpp_con.username);
|
||||
xmpp_syslog(SDEBUG,"XMPP password: %s", cur_xmpp_con.password);
|
||||
xmpp_syslog(SDEBUG,"XMPP domain: %s", cur_xmpp_con.domain);
|
||||
xmpp_syslog(SDEBUG,"XMPP resource: %s", cur_xmpp_con.resource);
|
||||
xmpp_syslog(SDEBUG,"XMPP use_tls: %d", cur_xmpp_con.usetls);
|
||||
xmpp_syslog(SDEBUG,"XMPP serveralgorithm: %s", cur_xmpp_con.serveralgorithm);
|
||||
xmpp_syslog(SDEBUG,"XMPP server_address: %s", cur_xmpp_con.serveraddress);
|
||||
xmpp_syslog(SDEBUG,"XMPP port: %d", cur_xmpp_con.port);
|
||||
xmpp_syslog(SDEBUG,"XMPP keepalive_interval: %d", cur_xmpp_con.keepalive_interval);
|
||||
xmpp_syslog(SDEBUG,"XMPP connect_attempt: %d", cur_xmpp_con.connect_attempt);
|
||||
xmpp_syslog(SDEBUG,"XMPP retry_initial_interval: %d", cur_xmpp_con.retry_initial_interval);
|
||||
xmpp_syslog(SDEBUG,"XMPP retry_interval_multiplier: %d", cur_xmpp_con.retry_interval_multiplier);
|
||||
xmpp_syslog(SDEBUG,"XMPP retry_max_interval: %d", cur_xmpp_con.retry_max_interval);
|
||||
|
||||
xmpp_uci_fini();
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
xmpp_global_conf();
|
||||
xmpp_syslog(SINFO,"START XMPP");
|
||||
|
||||
xmpp_con_init();
|
||||
xmpp_connecting();
|
||||
|
||||
xmpp_syslog(SINFO,"EXIT XMPP");
|
||||
xmpp_con_exit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
|
||||
*
|
||||
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _XMPP_H_
|
||||
#define _XMPP_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define XMPP_CR_NS "urn:broadband-forum-org:cwmp:xmppConnReq-1-0"
|
||||
#define XMPP_ERROR_NS "urn:ietf:params:xml:ns:xmpp-stanzas"
|
||||
#define DEFAULT_RETRY_INITIAL_INTERVAL 60
|
||||
#define DEFAULT_RETRY_INTERVAL_MULTIPLIER 2000
|
||||
#define DEFAULT_RETRY_MAX_INTERVAL 60
|
||||
#define DEFAULT_XMPP_RECONNECTION_RETRY 5
|
||||
|
||||
#ifndef FREE
|
||||
#define FREE(x) do { if(x) {free(x); x = NULL;} } while (0)
|
||||
#endif
|
||||
|
||||
enum xmpp_cr_error {
|
||||
XMPP_CR_NO_ERROR = 0,
|
||||
XMPP_SERVICE_UNAVAILABLE,
|
||||
XMPP_NOT_AUTHORIZED
|
||||
};
|
||||
|
||||
struct xmpp_config
|
||||
{
|
||||
char *xmpp_allowed_jid;
|
||||
int xmpp_loglevel;
|
||||
};
|
||||
|
||||
struct xmpp_connection
|
||||
{
|
||||
char *username;
|
||||
char *password;
|
||||
char *domain;
|
||||
char *resource;
|
||||
char *serveralgorithm;
|
||||
char *serveraddress;
|
||||
int keepalive_interval;
|
||||
int connect_attempt;
|
||||
int retry_initial_interval;
|
||||
int retry_interval_multiplier;
|
||||
int retry_max_interval;
|
||||
int port;
|
||||
bool usetls;
|
||||
};
|
||||
|
||||
extern struct xmpp_config cur_xmpp_conf;
|
||||
|
||||
#endif /* _XMPP_H_ */
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
# README #
|
||||
|
||||
In order to reach the devices that are connected behind NAT, the cwmp protocol introduces alternative method of executing Connection Request via NAT based on XMPP. The xmppd is an implementation of XMPP functionality that performs this feature.
|
||||
|
||||
## Configuration File ##
|
||||
|
||||
The xmppd UCI configuration is located in **'/etc/config/xmpp'**, and contains 3 sections: **xmpp**, **xmpp\_connection** and **xmpp\_connection\_server**.
|
||||
|
||||
```
|
||||
config xmpp 'xmpp'
|
||||
option enable '0'
|
||||
option id '0'
|
||||
option allowed_jid ''
|
||||
option loglevel '3'
|
||||
|
||||
config connection
|
||||
option enable '0'
|
||||
option username ''
|
||||
option password ''
|
||||
option domain ''
|
||||
option resource ''
|
||||
option serveralgorithm 'DNS-SRV'
|
||||
|
||||
config connection_server
|
||||
option con_id '1'
|
||||
option enable '0'
|
||||
option port '5222'
|
||||
```
|
||||
|
||||
### xmpp section ###
|
||||
|
||||
It defines **the xmpp section configuration**: enable, id, etc... The possible options for **xmpp** section are listed in the table below.
|
||||
|
||||
| Name | Type | Description |
|
||||
| --------------| ------- | --------------------------------------------- |
|
||||
| `enable` | boolean | If set to **1**, it enables the XMPP feature. |
|
||||
| `id` | integer | The id of XMPP connection. |
|
||||
| `allowed_jid` | string | The list of Jabber IDs or addresses that are allowed to initiate an XMPP Connection Request. |
|
||||
| `loglevel` | integer | The log type to use, by default it is set to **'INFO'**. The possible types are **'EMERG', 'ALERT', 'CRITIC' ,'ERROR', 'WARNING', 'NOTICE', 'INFO' and 'DEBUG'**. |
|
||||
|
||||
### connection section ###
|
||||
|
||||
It defines the xmpp\_connection section configuration**: enable, connection\_instance, username, etc... The possible options for **xmpp\_connection** section are listed in the table below.
|
||||
|
||||
| Name | Type | Description |
|
||||
| --------------------------- | ------- | ----------------------------------------------------- |
|
||||
| `con_inst` | integer | The instance number of the XMPP connection. |
|
||||
| `enable` | boolean | If set to **1**, it enables the XMPP connection. |
|
||||
| `con_alias` | string | The alias of the XMPP connection. |
|
||||
| `username` | string | The username of the XMPP connection. |
|
||||
| `password` | string | The password of the XMPP connection. |
|
||||
| `domain` | string | The proposed domain-part of the Jabber ID of the XMPP connection. |
|
||||
| `resource` | string | The proposed resource-part of the Jabber ID of the XMPP connection. |
|
||||
| `usetls` | boolean | If set to **1**, the CPE will initiate TLS negotiation. |
|
||||
| `interval` | integer | The number of seconds, that keep alive events are sent by the XMPP connection. |
|
||||
| `attempt` | string | The number of times that the Connection attempts to connect to a given IP address. |
|
||||
| `initial_retry_interval` | integer | The maximum first reconnection wait interval in seconds. |
|
||||
| `retry_interval_multiplier` | integer | The reconnection interval multiplier. |
|
||||
| `retry_max_interval` | integer | The maximum reconnection wait interval in seconds. |
|
||||
| `serveralgorithm` | string | The algorithm used when connecting with the XMPP server. Two algorithms are supported: **'DNS-SRV' and 'ServerTable'**. |
|
||||
|
||||
|
||||
### connection_server section ###
|
||||
|
||||
It defines **the xmpp\_connection\_server section configuration**: id\_connection, enable, port, etc... The possible options for **xmpp\_connection\_server** section are listed in the table below.
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---------------------------- | ------- | ------------------------------ |
|
||||
| `con_id` | string | The id XMPP connection to use. |
|
||||
| `con_srv_inst` | integer | The instance number of the XMPP server. |
|
||||
| `enable` | boolean | If set to **1**, it enables this XMPP server. |
|
||||
| `con_srv_alias` | string | The alias of the XMPP connection. |
|
||||
| `port` | integer | The port of the XMPP connection. |
|
||||
| `server_address` | string | The server address of the XMPP connection. |
|
||||
|
||||
## Dependencies ##
|
||||
|
||||
To successfully build xmpp, the following libraries are needed:
|
||||
|
||||
| Dependency | Link | License |
|
||||
| ----------- | --------------------------------------- | -------------- |
|
||||
| libuci | https://git.openwrt.org/project/uci.git | LGPL 2.1 |
|
||||
| libstrophe | https://github.com/strophe/libstrophe | GPL 3.0 |
|
||||
|
||||
252
xmpp/src/xuci.c
252
xmpp/src/xuci.c
|
|
@ -1,252 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
|
||||
*
|
||||
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "xuci.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static struct uci_context *uci_ctx = NULL;
|
||||
|
||||
void xmpp_uci_init(void)
|
||||
{
|
||||
uci_ctx = uci_alloc_context();
|
||||
}
|
||||
|
||||
void xmpp_uci_fini(void)
|
||||
{
|
||||
if (uci_ctx)
|
||||
uci_free_context(uci_ctx);
|
||||
}
|
||||
|
||||
static bool xmpp_uci_validate_section(const char *str)
|
||||
{
|
||||
if (!*str)
|
||||
return false;
|
||||
|
||||
for (; *str; str++) {
|
||||
unsigned char c = *str;
|
||||
|
||||
if (isalnum(c) || c == '_')
|
||||
continue;
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int xmpp_uci_init_ptr(struct uci_context *ctx, struct uci_ptr *ptr, const char *package, const char *section, const char *option, const char *value)
|
||||
{
|
||||
memset(ptr, 0, sizeof(struct uci_ptr));
|
||||
|
||||
/* value */
|
||||
if (value) {
|
||||
ptr->value = value;
|
||||
}
|
||||
ptr->package = package;
|
||||
if (!ptr->package)
|
||||
goto error;
|
||||
|
||||
ptr->section = section;
|
||||
if (!ptr->section) {
|
||||
ptr->target = UCI_TYPE_PACKAGE;
|
||||
goto lastval;
|
||||
}
|
||||
|
||||
ptr->option = option;
|
||||
if (!ptr->option) {
|
||||
ptr->target = UCI_TYPE_SECTION;
|
||||
goto lastval;
|
||||
} else {
|
||||
ptr->target = UCI_TYPE_OPTION;
|
||||
}
|
||||
|
||||
lastval:
|
||||
if (ptr->section && !xmpp_uci_validate_section(ptr->section))
|
||||
ptr->flags |= UCI_LOOKUP_EXTENDED;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct uci_section *xmpp_uci_walk_section(const char *package, const char *section_type, struct uci_section *prev_section)
|
||||
{
|
||||
struct uci_ptr ptr;
|
||||
struct uci_element *e;
|
||||
struct uci_section *next_section;
|
||||
|
||||
if (section_type == NULL) {
|
||||
if (prev_section) {
|
||||
e = &prev_section->e;
|
||||
if (e->list.next == &prev_section->package->sections)
|
||||
return NULL;
|
||||
e = container_of(e->list.next, struct uci_element, list);
|
||||
next_section = uci_to_section(e);
|
||||
return next_section;
|
||||
} else {
|
||||
if (xmpp_uci_init_ptr(uci_ctx, &ptr, package, NULL, NULL, NULL))
|
||||
return NULL;
|
||||
|
||||
if (uci_lookup_ptr(uci_ctx, &ptr, NULL, true) != UCI_OK)
|
||||
return NULL;
|
||||
|
||||
if (ptr.p->sections.next == &ptr.p->sections)
|
||||
return NULL;
|
||||
|
||||
e = container_of(ptr.p->sections.next, struct uci_element, list);
|
||||
next_section = uci_to_section(e);
|
||||
|
||||
return next_section;
|
||||
}
|
||||
} else {
|
||||
struct uci_list *ul, *shead = NULL;
|
||||
|
||||
if (prev_section) {
|
||||
ul = &prev_section->e.list;
|
||||
shead = &prev_section->package->sections;
|
||||
} else {
|
||||
if (xmpp_uci_init_ptr(uci_ctx, &ptr, package, NULL, NULL, NULL))
|
||||
return NULL;
|
||||
|
||||
if (uci_lookup_ptr(uci_ctx, &ptr, NULL, true) != UCI_OK)
|
||||
return NULL;
|
||||
|
||||
ul = &ptr.p->sections;
|
||||
shead = &ptr.p->sections;
|
||||
}
|
||||
|
||||
while (ul->next != shead) {
|
||||
e = container_of(ul->next, struct uci_element, list);
|
||||
next_section = uci_to_section(e);
|
||||
if (strcmp(next_section->type, section_type) == 0)
|
||||
return next_section;
|
||||
ul = ul->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void xmpp_uci_print_list(struct uci_list *uh, char **val, char *delimiter)
|
||||
{
|
||||
struct uci_element *e;
|
||||
static char buffer[512];
|
||||
char *buf = buffer;
|
||||
*buf = '\0';
|
||||
|
||||
uci_foreach_element(uh, e) {
|
||||
if (*buf) {
|
||||
strcat(buf, delimiter);
|
||||
strcat(buf, e->name);
|
||||
} else {
|
||||
strcpy(buf, e->name);
|
||||
}
|
||||
}
|
||||
*val = buf;
|
||||
}
|
||||
|
||||
static struct uci_element *xmpp_uci_lookup_list(struct uci_list *list, const char *name)
|
||||
{
|
||||
struct uci_element *e;
|
||||
|
||||
uci_foreach_element(list, e) {
|
||||
if (!strcmp(e->name, name))
|
||||
return e;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int uci_lookup_ptr_bysection(struct uci_context *ctx, struct uci_ptr *ptr, struct uci_section *section, const char *option, const char *value)
|
||||
{
|
||||
struct uci_element *e;
|
||||
memset(ptr, 0, sizeof(struct uci_ptr));
|
||||
|
||||
ptr->package = section->package->e.name;
|
||||
ptr->section = section->e.name;
|
||||
ptr->option = option;
|
||||
ptr->value = value;
|
||||
ptr->flags |= UCI_LOOKUP_DONE;
|
||||
|
||||
ptr->p = section->package;
|
||||
ptr->s = section;
|
||||
|
||||
if (ptr->option) {
|
||||
e = xmpp_uci_lookup_list(&ptr->s->options, ptr->option);
|
||||
if (!e)
|
||||
return UCI_OK;
|
||||
ptr->o = uci_to_option(e);
|
||||
ptr->last = e;
|
||||
ptr->target = UCI_TYPE_OPTION;
|
||||
} else {
|
||||
ptr->last = &ptr->s->e;
|
||||
ptr->target = UCI_TYPE_SECTION;
|
||||
}
|
||||
|
||||
ptr->flags |= UCI_LOOKUP_COMPLETE;
|
||||
|
||||
return UCI_OK;
|
||||
}
|
||||
|
||||
const char *xmpp_uci_get_value_bysection(struct uci_section *section, const char *option)
|
||||
{
|
||||
struct uci_ptr ptr;
|
||||
char *val = "";
|
||||
|
||||
if (uci_lookup_ptr_bysection(uci_ctx, &ptr, section, option, NULL) != UCI_OK)
|
||||
return val;
|
||||
|
||||
if (!ptr.o)
|
||||
return val;
|
||||
|
||||
if(ptr.o->type == UCI_TYPE_LIST) {
|
||||
xmpp_uci_print_list(&ptr.o->v.list, &val, " ");
|
||||
return val;
|
||||
}
|
||||
|
||||
if (ptr.o->v.string)
|
||||
return ptr.o->v.string;
|
||||
else
|
||||
return val;
|
||||
}
|
||||
|
||||
const char *xmpp_uci_get_value(const char *package, const char *section, const char *option)
|
||||
{
|
||||
struct uci_ptr ptr;
|
||||
char *val = "";
|
||||
|
||||
if (!section || !option)
|
||||
return val;
|
||||
|
||||
if (xmpp_uci_init_ptr(uci_ctx, &ptr, package, section, option, NULL))
|
||||
return val;
|
||||
|
||||
if (uci_lookup_ptr(uci_ctx, &ptr, NULL, true) != UCI_OK)
|
||||
return val;
|
||||
|
||||
if (!ptr.o)
|
||||
return val;
|
||||
|
||||
if (ptr.o->v.string)
|
||||
return ptr.o->v.string;
|
||||
else
|
||||
return val;
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
|
||||
*
|
||||
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _XMPPUCI_H_
|
||||
#define _XMPPUCI_H_
|
||||
|
||||
#include <uci.h>
|
||||
|
||||
void xmpp_uci_init(void);
|
||||
void xmpp_uci_fini(void);
|
||||
|
||||
struct uci_section *xmpp_uci_walk_section(const char *package, const char *section_type, struct uci_section *prev_section);
|
||||
const char *xmpp_uci_get_value_bysection(struct uci_section *section, const char *option);
|
||||
const char *xmpp_uci_get_value(const char *package, const char *section, const char *option);
|
||||
|
||||
#define xmpp_uci_foreach_section(package, section_type, section) \
|
||||
for (section = xmpp_uci_walk_section(package, section_type, NULL); \
|
||||
section != NULL; \
|
||||
section = xmpp_uci_walk_section(package, section_type, section))
|
||||
|
||||
#endif /* _XMPPUCI_H_ */
|
||||
|
|
@ -7,11 +7,21 @@
|
|||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=xmpp
|
||||
PKG_NAME:=xmppc
|
||||
PKG_VERSION:=1.0.0
|
||||
|
||||
PKG_SOURCE_VERSION:=231b010d5578bedee5f37de3ad7bd65e57f13a31
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://dev.iopsys.eu/iopsys/xmppc.git
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
PKG_MIRROR_HASH:=skip
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
|
||||
PKG_LICENSE:=GPL-2.0-only
|
||||
PKG_LICENSE_FILES:=LICENSE
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/$(PKG_NAME)
|
||||
|
|
@ -26,10 +36,6 @@ define Package/$(PKG_NAME)/description
|
|||
BBF XMPP Client
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
$(CP) ./src/* $(PKG_BUILD_DIR)/
|
||||
endef
|
||||
|
||||
TARGET_CFLAGS += \
|
||||
-D_GNU_SOURCE
|
||||
|
||||
|
|
@ -41,4 +47,4 @@ define Package/$(PKG_NAME)/install
|
|||
$(CP) ./files/* $(1)/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,$(PKG_NAME)))
|
||||
$(eval $(call BuildPackage,$(PKG_NAME)))
|
||||
Loading…
Add table
Reference in a new issue