Browse Source

update: json configure file decode

master
dnomd343 2 years ago
parent
commit
b9bff149dc
  1. 19
      include/common.h
  2. 2
      include/help.h
  3. 6
      include/load.h
  4. 0
      include/logger.h
  5. 278
      src/common.c
  6. 267
      src/load.c
  7. 8
      src/local.c
  8. 2
      src/logger.c
  9. 6
      src/server.c

19
include/common.h

@ -1,23 +1,13 @@
#ifndef _COMMON_H_
#define _COMMON_H_
#define VERSION "0.9.1"
#define RANDOM_PORT_START 41952
#define RANDOM_PORT_END 65535
//extern int is_udp_proxy;
//extern char *server_addr, *client_addr;
//extern char *server_port, *client_port;
//extern char *password;
//extern char *method;
//extern char *timeout;
//extern int fastopen;
//extern char *plugin;
//extern char *plugin_opts;
//extern char *shadowsocks;
//extern char **shadowsocks_opts;
typedef struct {
int is_debug, is_udp_proxy;
int is_udp_proxy;
char *server_addr, *client_addr;
char *server_port, *client_port;
char *password;
@ -30,6 +20,9 @@ typedef struct {
char **shadowsocks_opts;
} bootstrap_info;
char* int_to_string(int num);
char* new_string(char *str);
char* read_file(char *file_name);
void params_load(char *ss_default, bootstrap_info *info);
void args_decode(int argc, char **argv, bootstrap_info *info);

2
include/help.h

@ -1,8 +1,6 @@
#ifndef _HELP_H_
#define _HELP_H_
#define VERSION "0.9.0"
extern char *local_help_msg;
extern char *server_help_msg;

6
include/load.h

@ -0,0 +1,6 @@
#ifndef _LOAD_H_
#define _LOAD_H_
void load_info(int argc, char **argv);
#endif

0
include/log.h → include/logger.h

278
src/common.c

@ -5,7 +5,7 @@
#include "common.h"
#include "network.h"
#include "process.h"
#include "log.h"
#include "logger.h"
//int is_udp_proxy = 1;
//char *server_addr = NULL, *client_addr = NULL;
@ -91,7 +91,7 @@ void params_load(char *ss_default, bootstrap_info *info) { // load shadowsocks a
//}
char* read_file(char *file_name) { // read file content
log_debug("Read file content -> %s", file_name);
log_debug("Start read file -> %s", file_name);
FILE *pfile = fopen(file_name, "rb");
if (pfile == NULL) { // file open failed
log_fatal("File `%s` open failed", file_name);
@ -110,29 +110,7 @@ char* read_file(char *file_name) { // read file content
return file_content;
}
void extra_options_decode(char *extra_opts, char **opts) { // decode shadowsocks extra options
int num, i;
char *tmp = (char*)calloc(strlen(extra_opts) + 1, 1); // new memory and set as 0x00
num = i = 0;
for (;;) {
if (extra_opts[num] == '\0' || extra_opts[num] == ' ') { // string end or find a space
tmp[i] = '\0';
if (i) { // ignore empty string
add_shadowsocks_option(tmp, opts);
}
if (extra_opts[num] == '\0') { // string end
break;
}
num++;
i = 0;
continue;
}
if (extra_opts[num] == '\\') { // skip '\' char
num++;
}
tmp[i++] = extra_opts[num++]; // copy char
}
}
void add_shadowsocks_option(char *option, char **opts) { // add shadowsocks options
int opt_num = 0;
@ -176,150 +154,7 @@ void pack_shadowsocks_params(bootstrap_info *info) { // packaging shadowsocks pa
}
}
void json_decode(char *json_content, bootstrap_info *info) { // decode JSON content
cJSON* json = NULL;
json = cJSON_Parse(json_content);
if (json == NULL) {
log_fatal("JSON format error.");
}
json = json->child;
while (json != NULL) {
if (!strcmp(json->string, "no_udp")) { // no_udp => without udp proxy
if (!cJSON_IsBool(json)) {
log_fatal("`no_udp` must be a bool.");
}
if (json->valueint) { // is_udp_proxy = ~(json->valueint)
info->is_udp_proxy = 0;
} else {
info->is_udp_proxy = 1;
}
} else if (!strcmp(json->string, "server")) { // server => server_addr
if (!cJSON_IsString(json)) {
log_fatal("`server` must be a string.");
}
if (info->server_addr != NULL) {
free(info->server_addr);
}
info->server_addr = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring);
} else if (!strcmp(json->string, "local_address")) { // local_address => client_addr
if (!cJSON_IsString(json)) {
log_fatal("`local_address` must be a string.");
}
if (info->client_addr != NULL) {
free(info->client_addr);
}
info->client_addr = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring);
} else if (!strcmp(json->string, "server_port")) { // server_port => server_port
if (info->server_port != NULL) {
free(info->server_port);
}
if (cJSON_IsNumber(json)) {
info->server_port = int_to_string(json->valueint);
} else if (cJSON_IsString(json)) {
info->server_port = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring);
} else {
log_fatal("`server_port` must be a number or string.");
}
} else if (!strcmp(json->string, "local_port")) { // local_port => client_port
if (info->client_port != NULL) {
free(info->client_port);
}
if (cJSON_IsNumber(json)) {
info->client_port = int_to_string(json->valueint);
} else if (cJSON_IsString(json)) {
info->client_port = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring);
} else {
log_fatal("`local_port` must be a number or string.");
}
} else if (!strcmp(json->string, "password")) { // password => password
if (!cJSON_IsString(json)) {
log_fatal("`password` must be a string.");
}
if (info->password != NULL) {
free(info->password);
}
info->password = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring);
} else if (!strcmp(json->string, "timeout")) { // timeout => timeout
if (info->timeout != NULL) {
free(info->timeout);
}
if (cJSON_IsNumber(json)) {
info->timeout = int_to_string(json->valueint);
} else if (cJSON_IsString(json)) {
info->timeout = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring);
} else {
log_fatal("`timeout` must be a number or string.");
}
} else if (!strcmp(json->string, "method")) { // method => method
if (!cJSON_IsString(json)) {
log_fatal("`method` must be a string.");
}
if (info->method != NULL) {
free(info->method);
}
info->method = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring);
} else if (!strcmp(json->string, "fast_open")) { // fast_open => fastopen
if (!cJSON_IsBool(json)) {
log_fatal("`fast_open` must be a bool.");
}
info->fastopen = json->valueint;
} else if (!strcmp(json->string, "plugin")) { // plugin => plugin
if (!cJSON_IsString(json)) {
log_fatal("`plugin` must be a string.");
}
if (info->plugin != NULL) {
free(info->plugin);
}
info->plugin = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring);
} else if (!strcmp(json->string, "plugin_opts")) { // plugin_opts => plugin_opts
if (!cJSON_IsString(json)) {
log_fatal("`plugin_opts` must be a string.");
}
if (info->plugin_opts != NULL) {
free(info->plugin_opts);
}
info->plugin_opts = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring);
} else if (!strcmp(json->string, "shadowsocks")) { // shadowsocks => shadowsocks
if (!cJSON_IsString(json)) {
log_fatal("`shadowsocks` must be a string.");
}
if (info->shadowsocks != NULL) {
free(info->shadowsocks);
}
info->shadowsocks = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring);
} else if (!strcmp(json->string, "extra_opts")) { // extra_opts => DECODE => shadowsocks_opts
if (!cJSON_IsString(json)) {
log_fatal("`extra_opts` must be a string.");
}
extra_options_decode(json->valuestring, info->shadowsocks_opts);
} else { // unknown field => ERROR
char *msg_prefix = "Unknown JSON field `";
char *msg_suffix = "`.\n";
char *msg = (char*)malloc(strlen(msg_prefix) + strlen(json->string) + strlen(msg_suffix) + 1);
strcpy(msg, msg_prefix);
log_fatal(strcat(strcat(msg, json->string), msg_suffix));
}
json = json->next; // next field
}
cJSON_free(json); // free JSON struct
}
void args_init(bootstrap_info *info) {
info->is_debug = 0; // disable debug mode
info->is_udp_proxy = 1; // enable udp proxy
info->server_addr = info->client_addr = NULL;
info->server_port = info->client_port = NULL;
info->password = NULL;
info->method = NULL;
info->timeout = NULL;
info->fastopen = 0;
info->plugin = NULL;
info->plugin_opts = NULL;
info->shadowsocks = NULL;
info->shadowsocks_opts = (char**)malloc(sizeof(char*) * 2); // 2 arguments
info->shadowsocks_opts[0] = ""; // reserved for program name
info->shadowsocks_opts[1] = NULL;
}
char* new_string(char *str) {
return strcpy((char*)malloc(strlen(str) + 1), str);
@ -354,113 +189,6 @@ void args_debug(bootstrap_info *info) {
}
}
void args_decode(int argc, char **argv, bootstrap_info *info) { // decode the input parameters
args_init(info);
for (int i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "--debug")) { // --debug ==> debug mode
info->is_debug = 1;
} else if (!strcmp(argv[i], "--no-udp")) { // --no-udp ==> without udp proxy
info->is_udp_proxy = 0;
} else if (!strcmp(argv[i], "-c")) { // -c ==> CONFIG_JSON
if (++i == argc) {
log_fatal("`-c` require a parameter");
}
char *json_content = read_file(argv[i]);
json_decode(json_content, info); // decode json content
free(json_content);
} else if (!strcmp(argv[i], "-s")) { // -s ==> server_addr
if (++i == argc) {
log_fatal("`-s` require a parameter");
}
if (info->server_addr != NULL) {
free(info->server_addr); // override server address
}
info->server_addr = new_string(argv[i]);
} else if (!strcmp(argv[i], "-p")) { // -p ==> server_port
if (++i == argc) {
log_fatal("`-p` require a parameter");
}
if (info->server_port != NULL) {
free(info->server_port); // override server port
}
info->server_port = new_string(argv[i]);
} else if (!strcmp(argv[i], "-b")) { // -b ==> client_addr
if (++i == argc) {
log_fatal("`-b` require a parameter");
}
if (info->client_addr != NULL) {
free(info->client_addr); // override client address
}
info->client_addr = new_string(argv[i]);
} else if (!strcmp(argv[i], "-l")) { // -l ==> client_port
if (++i == argc) {
log_fatal("`-l` require a parameter");
}
if (info->client_port != NULL) {
free(info->client_port); // override client port
}
info->client_port = new_string(argv[i]);
} else if (!strcmp(argv[i], "-k")) { // -k ==> password
if (++i == argc) {
log_fatal("`-k` require a parameter");
}
if (info->password != NULL) {
free(info->password); // override password
}
info->password = new_string(argv[i]);
} else if (!strcmp(argv[i], "-m")) { // -m ==> method
if (++i == argc) {
log_fatal("`-m` require a parameter");
}
if (info->method != NULL) {
free(info->method); // override method
}
info->method = new_string(argv[i]);
} else if (!strcmp(argv[i], "-t")) { // -t ==> timeout
if (++i == argc) {
log_fatal("`-t` require a parameter");
}
if (info->timeout != NULL) {
free(info->timeout); // override timeout
}
info->timeout = new_string(argv[i]);
} else if (!strcmp(argv[i], "--fast-open")) { // --fast-open
info->fastopen = 1;
} else if (!strcmp(argv[i], "--plugin")) { // --plugin ==> plugin
if (++i == argc) {
log_fatal("`--plugin` require a parameter");
}
if (info->plugin != NULL) {
free(info->plugin); // override plugin
}
info->plugin = new_string(argv[i]);
} else if (!strcmp(argv[i], "--plugin-opts")) { // --plugin-opts ==> plugin_opts
if (++i == argc) {
log_fatal("`--plugin-opts` require a parameter");
}
if (info->plugin_opts != NULL) {
free(info->plugin_opts);
}
info->plugin_opts = new_string(argv[i]);
} else if (!strcmp(argv[i], "--shadowsocks")) { // --shadowsocks ==> shadowsocks
if (++i == argc) {
log_fatal("`--shadowsocks` require a parameter");
}
if (info->shadowsocks != NULL) {
free(info->shadowsocks);
}
info->shadowsocks = new_string(argv[i]);
} else { // unknown option ==> archive
add_shadowsocks_option(argv[i], info->shadowsocks_opts); // archive unknown options
}
}
if (info->server_addr == NULL) { // default server address (bind address in server mode)
info->server_addr = "127.0.0.1";
}
args_debug(info);
}
//void args_dump() { // show parameter's content
//

267
src/load.c

@ -0,0 +1,267 @@
#include <stdlib.h>
#include <string.h>
#include "load.h"
#include "common.h"
#include "logger.h"
#include "cJSON.h"
void init_info(bootstrap_info *info) {
info->is_udp_proxy = 1; // enabled udp proxy
info->server_addr = info->client_addr = NULL;
info->server_port = info->client_port = NULL;
info->password = NULL;
info->method = NULL;
info->timeout = NULL;
info->fastopen = 0;
info->plugin = NULL;
info->plugin_opts = NULL;
info->shadowsocks = NULL;
info->shadowsocks_opts = (char**)malloc(sizeof(char*) * 2); // two arguments
info->shadowsocks_opts[0] = ""; // reserved for program name
// TODO: add reserved field after load
info->shadowsocks_opts[1] = NULL;
}
void dump_info(bootstrap_info *info) {
if (info->is_udp_proxy) {
log_debug("is_udp_proxy = true");
} else {
log_debug("is_udp_proxy = false");
}
log_debug("server_addr = %s", info->server_addr);
log_debug("client_addr = %s", info->client_addr);
log_debug("server_port = %s", info->server_port);
log_debug("client_port = %s", info->client_port);
log_debug("password = %s", info->password);
log_debug("method = %s", info->method);
log_debug("timeout = %s", info->timeout);
if (info->fastopen) {
log_debug("fastopen = true");
} else {
log_debug("fastopen = false");
}
log_debug("plugin = %s", info->plugin);
log_debug("plugin_opts = %s", info->plugin_opts);
log_debug("shadowsocks = %s", info->shadowsocks);
log_debug("shadowsocks_opts:"); // TODO: combine as one line output
char **option = info->shadowsocks_opts;
while(*option != NULL) {
printf(" '%s'\n", *option);
++option;
}
}
char** string_list_append(char **string_list, char *data) {
int num = 0;
while(string_list[num++] != NULL); // get string list size
string_list = (char**)realloc(string_list, sizeof(char**) * (num + 1));
string_list[num - 1] = new_string(data);
string_list[num] = NULL; // list end sign
return string_list;
}
int load_field(char *field, char **target, char ***arg, char ***arg_limit) {
if (strcmp(**arg, field)) { // field not match
return 0;
}
if (++(*arg) == *arg_limit) { // without next argument
log_fatal("`%s` require a parameter", field);
}
if (*target != NULL) {
free(*target); // override target field
}
*target = new_string(**arg);
return 1;
}
char** add_extra_options(char **opts, char *extra_opts_str) { // split shadowsocks extra options
log_debug("Split extra options -> `%s`", extra_opts_str);
char *tmp = (char*)calloc(strlen(extra_opts_str) + 1, 1); // new memory and set as 0x00
for (int i = 0, num = 0;; ++num) {
if (extra_opts_str[num] == '\0' || extra_opts_str[num] == ' ') { // string end or find a space
tmp[i] = '\0';
if (i) { // ignore empty string
i = 0;
opts = string_list_append(opts, tmp);
}
if (extra_opts_str[num] == '\0') { // string end
break;
}
continue;
}
if (extra_opts_str[num] == '\\') { // skip '\' char
++num;
}
tmp[i++] = extra_opts_str[num]; // copy char
}
return opts;
}
void json_decode(char *json_content, bootstrap_info *info) { // decode JSON content
cJSON* json = cJSON_Parse(json_content);
if (json == NULL) {
log_fatal("JSON format error");
}
json = json->child;
while (json != NULL) {
if (!strcmp(json->string, "no_udp")) { // no_udp => without udp proxy
if (!cJSON_IsBool(json)) {
log_fatal("`no_udp` must be bool");
}
if (json->valueint) { // is_udp_proxy = ~(json->valueint)
info->is_udp_proxy = 0;
} else {
info->is_udp_proxy = 1;
}
} else if (!strcmp(json->string, "server")) { // server => server_addr
if (!cJSON_IsString(json)) {
log_fatal("`server` must be string");
}
if (info->server_addr != NULL) {
free(info->server_addr);
}
info->server_addr = new_string(json->valuestring);
} else if (!strcmp(json->string, "local_address")) { // local_address => client_addr
if (!cJSON_IsString(json)) {
log_fatal("`local_address` must be string");
}
if (info->client_addr != NULL) {
free(info->client_addr);
}
info->client_addr = new_string(json->valuestring);
} else if (!strcmp(json->string, "server_port")) { // server_port => server_port
if (info->server_port != NULL) {
free(info->server_port);
}
if (cJSON_IsNumber(json)) {
info->server_port = int_to_string(json->valueint);
} else if (cJSON_IsString(json)) {
info->server_port = new_string(json->valuestring);
} else {
log_fatal("`server_port` must be number or string");
}
} else if (!strcmp(json->string, "local_port")) { // local_port => client_port
if (info->client_port != NULL) {
free(info->client_port);
}
if (cJSON_IsNumber(json)) {
info->client_port = int_to_string(json->valueint);
} else if (cJSON_IsString(json)) {
info->client_port = new_string(json->valuestring);
} else {
log_fatal("`local_port` must be number or string");
}
} else if (!strcmp(json->string, "password")) { // password => password
if (!cJSON_IsString(json)) {
log_fatal("`password` must be string");
}
if (info->password != NULL) {
free(info->password);
}
info->password = new_string(json->valuestring);
} else if (!strcmp(json->string, "timeout")) { // timeout => timeout
if (info->timeout != NULL) {
free(info->timeout);
}
if (cJSON_IsNumber(json)) {
info->timeout = int_to_string(json->valueint);
} else if (cJSON_IsString(json)) {
info->timeout = new_string(json->valuestring);
} else {
log_fatal("`timeout` must be number or string");
}
} else if (!strcmp(json->string, "method")) { // method => method
if (!cJSON_IsString(json)) {
log_fatal("`method` must be string");
}
if (info->method != NULL) {
free(info->method);
}
info->method = new_string(json->valuestring);
} else if (!strcmp(json->string, "fast_open")) { // fast_open => fastopen
if (!cJSON_IsBool(json)) {
log_fatal("`fast_open` must be bool");
}
info->fastopen = json->valueint;
} else if (!strcmp(json->string, "plugin")) { // plugin => plugin
if (!cJSON_IsString(json)) {
log_fatal("`plugin` must be string");
}
if (info->plugin != NULL) {
free(info->plugin);
}
info->plugin = new_string(json->valuestring);
} else if (!strcmp(json->string, "plugin_opts")) { // plugin_opts => plugin_opts
if (!cJSON_IsString(json)) {
log_fatal("`plugin_opts` must be string");
}
if (info->plugin_opts != NULL) {
free(info->plugin_opts);
}
info->plugin_opts = new_string(json->valuestring);
} else if (!strcmp(json->string, "shadowsocks")) { // shadowsocks => shadowsocks
if (!cJSON_IsString(json)) {
log_fatal("`shadowsocks` must be string");
}
if (info->shadowsocks != NULL) {
free(info->shadowsocks);
}
info->shadowsocks = new_string(json->valuestring);
} else if (!strcmp(json->string, "extra_opts")) { // extra_opts => DECODE => shadowsocks_opts
if (!cJSON_IsString(json)) {
log_fatal("`extra_opts` must be string");
}
info->shadowsocks_opts = add_extra_options(info->shadowsocks_opts, json->valuestring);
} else { // unknown field => ERROR
log_fatal("Unknown JSON field `%s`", json->string);
}
json = json->next; // next field
}
cJSON_free(json); // free JSON struct
}
void load_info(int argc, char **argv) { // load info from input parameters
bootstrap_info *info = (bootstrap_info*)malloc(sizeof(bootstrap_info));
log_debug("Start to load input arguments");
// TODO: output input args
init_info(info);
char **arg_limit = argv + argc;
for (char **arg = argv + 1; arg < arg_limit; ++arg) {
// log_debug("Get argument -> `%s`", *arg);
if (!strcmp(*arg, "--debug")) { // skip debug flag
continue;
} else if (!strcmp(*arg, "--fast-open")) { // --fast-open => fastopen
info->fastopen = 1;
} else if (!strcmp(*arg, "--no-udp")) { // --no-udp => is_udp_proxy
info->is_udp_proxy = 0;
} else if (!strcmp(*arg, "-c")) { // -c => CONFIG_JSON
if (++arg == arg_limit) {
log_fatal("Miss json file after `-c` flag");
}
char *json_content = read_file(*arg);
json_decode(json_content, info); // decode json content
free(json_content);
} else if (
!load_field("-s", &info->server_addr, &arg, &arg_limit) &&
!load_field("-p", &info->server_port, &arg, &arg_limit) &&
!load_field("-b", &info->client_addr, &arg, &arg_limit) &&
!load_field("-l", &info->client_port, &arg, &arg_limit) &&
!load_field("-k", &info->password, &arg, &arg_limit) &&
!load_field("-m", &info->method, &arg, &arg_limit) &&
!load_field("-t", &info->timeout, &arg, &arg_limit) &&
!load_field("--plugin", &info->plugin, &arg, &arg_limit) &&
!load_field("--plugin-opts", &info->plugin_opts, &arg, &arg_limit) &&
!load_field("--shadowsocks", &info->shadowsocks, &arg, &arg_limit)
) { // archive unknown options
log_info("Extra field -> %s", *arg);
info->shadowsocks_opts = string_list_append(info->shadowsocks_opts, *arg);
}
}
if (info->server_addr == NULL) { // default server address (bind address in server mode)
info->server_addr = "127.0.0.1";
}
dump_info(info);
}

8
src/local.c

@ -4,14 +4,16 @@
#include "common.h"
#include "process.h"
#include "help.h"
#include "log.h"
#include "logger.h"
#include "load.h"
int main(int argc, char *argv[]) {
is_show_help(argc, argv, local_help_msg);
log_info("Shadowsocks bootstrap local (%s)", VERSION);
bootstrap_info info;
args_decode(argc, argv, &info);
// set log level
// bootstrap_info info;
load_info(argc, argv);
// params_load("sslocal"); // default file name
// start_bootstrap("sslocal", is_udp_proxy); // local or server mode
return 0;

2
src/log.c → src/logger.c

@ -1,5 +1,5 @@
#include <stdlib.h>
#include "log.h"
#include "logger.h"
int log_level = LOG_DEBUG; // default log level

6
src/server.c

@ -4,14 +4,14 @@
#include "common.h"
#include "process.h"
#include "help.h"
#include "log.h"
#include "logger.h"
int main(int argc, char *argv[]) {
is_show_help(argc, argv, server_help_msg);
log_info("Shadowsocks bootstrap server (%s)", VERSION);
bootstrap_info info;
args_decode(argc, argv, &info);
// bootstrap_info info;
// args_decode(argc, argv, &info);
// params_load("ssserver"); // default file name
// start_bootstrap("ssserver", is_udp_proxy); // local or server mode
return 0;

Loading…
Cancel
Save