|  |  | @ -5,38 +5,39 @@ | 
			
		
	
		
			
				
					|  |  |  | #include "common.h" | 
			
		
	
		
			
				
					|  |  |  | #include "network.h" | 
			
		
	
		
			
				
					|  |  |  | #include "process.h" | 
			
		
	
		
			
				
					|  |  |  | #include "log.h" | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | int is_udp_proxy; | 
			
		
	
		
			
				
					|  |  |  | char *server_addr, *client_addr; | 
			
		
	
		
			
				
					|  |  |  | char *server_port, *client_port; | 
			
		
	
		
			
				
					|  |  |  | char *password; | 
			
		
	
		
			
				
					|  |  |  | char *method; | 
			
		
	
		
			
				
					|  |  |  | char *timeout; | 
			
		
	
		
			
				
					|  |  |  | int fastopen; | 
			
		
	
		
			
				
					|  |  |  | char *plugin; | 
			
		
	
		
			
				
					|  |  |  | char *plugin_opts; | 
			
		
	
		
			
				
					|  |  |  | char *shadowsocks; | 
			
		
	
		
			
				
					|  |  |  | char **shadowsocks_opts; | 
			
		
	
		
			
				
					|  |  |  | //int is_udp_proxy = 1;
 | 
			
		
	
		
			
				
					|  |  |  | //char *server_addr = NULL, *client_addr = NULL;
 | 
			
		
	
		
			
				
					|  |  |  | //char *server_port = NULL, *client_port = NULL;
 | 
			
		
	
		
			
				
					|  |  |  | //char *password = NULL;
 | 
			
		
	
		
			
				
					|  |  |  | //char *method = NULL;
 | 
			
		
	
		
			
				
					|  |  |  | //char *timeout = NULL;
 | 
			
		
	
		
			
				
					|  |  |  | //int fastopen = 0;
 | 
			
		
	
		
			
				
					|  |  |  | //char *plugin = NULL;
 | 
			
		
	
		
			
				
					|  |  |  | //char *plugin_opts = NULL;
 | 
			
		
	
		
			
				
					|  |  |  | //char *shadowsocks = NULL;
 | 
			
		
	
		
			
				
					|  |  |  | //char **shadowsocks_opts; // init before usage
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | void args_dump(); | 
			
		
	
		
			
				
					|  |  |  | void args_init(); | 
			
		
	
		
			
				
					|  |  |  | void error_exit(char *msg); | 
			
		
	
		
			
				
					|  |  |  | //void error_exit(char *msg);
 | 
			
		
	
		
			
				
					|  |  |  | char* int_to_string(int num); | 
			
		
	
		
			
				
					|  |  |  | void pack_shadowsocks_params(); | 
			
		
	
		
			
				
					|  |  |  | void pack_shadowsocks_params(bootstrap_info *info); | 
			
		
	
		
			
				
					|  |  |  | char* read_file(char *file_name); | 
			
		
	
		
			
				
					|  |  |  | void json_decode(char *json_content); | 
			
		
	
		
			
				
					|  |  |  | void add_shadowsocks_option(char *option); | 
			
		
	
		
			
				
					|  |  |  | void extra_options_decode(char *extra_opts); | 
			
		
	
		
			
				
					|  |  |  | //void json_decode(char *json_content);
 | 
			
		
	
		
			
				
					|  |  |  | void add_shadowsocks_option(char *option, char **opts); | 
			
		
	
		
			
				
					|  |  |  | void extra_options_decode(char *extra_opts, char **opts); | 
			
		
	
		
			
				
					|  |  |  | //void params_load(char *ss_default, bootstrap_info *info);
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | void error_exit(char *msg) { // throw error message with exit-code 1
 | 
			
		
	
		
			
				
					|  |  |  |     printf("[Shadowsocks Bootstrap] ERROR: %s.\n", msg); | 
			
		
	
		
			
				
					|  |  |  |     printf("[Shadowsocks Bootstrap] exit with error.\n"); | 
			
		
	
		
			
				
					|  |  |  |     exit(1); | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | //void error_exit(char *msg) { // throw error message with exit-code 1
 | 
			
		
	
		
			
				
					|  |  |  | //    printf("[Shadowsocks Bootstrap] ERROR: %s.\n", msg);
 | 
			
		
	
		
			
				
					|  |  |  | //    printf("[Shadowsocks Bootstrap] exit with error.\n");
 | 
			
		
	
		
			
				
					|  |  |  | //    exit(1);
 | 
			
		
	
		
			
				
					|  |  |  | //}
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | char* int_to_string(int num) { // int -> string
 | 
			
		
	
		
			
				
					|  |  |  |     if (num < 0) { | 
			
		
	
		
			
				
					|  |  |  |         error_exit("number must be positive"); | 
			
		
	
		
			
				
					|  |  |  |         log_fatal("number must be positive"); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     int count = 0; | 
			
		
	
		
			
				
					|  |  |  |     int temp = num; | 
			
		
	
	
		
			
				
					|  |  | @ -49,69 +50,67 @@ char* int_to_string(int num) { // int -> string | 
			
		
	
		
			
				
					|  |  |  |     return str; | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | void params_load(char *ss_default) { // load shadowsocks and plugin params
 | 
			
		
	
		
			
				
					|  |  |  |     if (shadowsocks == NULL) { | 
			
		
	
		
			
				
					|  |  |  |         shadowsocks = ss_default; | 
			
		
	
		
			
				
					|  |  |  | void params_load(char *ss_default, bootstrap_info *info) { // load shadowsocks and plugin params
 | 
			
		
	
		
			
				
					|  |  |  |     if (info->shadowsocks == NULL) { | 
			
		
	
		
			
				
					|  |  |  |         info->shadowsocks = ss_default; | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     shadowsocks_opts[0] = shadowsocks; // fill with file name
 | 
			
		
	
		
			
				
					|  |  |  |     if (plugin != NULL) { // with plugin
 | 
			
		
	
		
			
				
					|  |  |  |     info->shadowsocks_opts[0] = info->shadowsocks; // fill with file name
 | 
			
		
	
		
			
				
					|  |  |  |     if (info->plugin != NULL) { // with plugin
 | 
			
		
	
		
			
				
					|  |  |  |         char *rand_port = int_to_string(get_available_port(RANDOM_PORT_START, RANDOM_PORT_END)); | 
			
		
	
		
			
				
					|  |  |  |         SS_REMOTE_HOST = server_addr; | 
			
		
	
		
			
				
					|  |  |  |         SS_REMOTE_PORT = server_port; | 
			
		
	
		
			
				
					|  |  |  |         SS_REMOTE_HOST = info->server_addr; | 
			
		
	
		
			
				
					|  |  |  |         SS_REMOTE_PORT = info->server_port; | 
			
		
	
		
			
				
					|  |  |  |         SS_LOCAL_HOST = "127.0.0.1"; | 
			
		
	
		
			
				
					|  |  |  |         SS_LOCAL_PORT = rand_port; | 
			
		
	
		
			
				
					|  |  |  |         server_addr = SS_LOCAL_HOST; | 
			
		
	
		
			
				
					|  |  |  |         server_port = SS_LOCAL_PORT; | 
			
		
	
		
			
				
					|  |  |  |         SS_PLUGIN_OPTIONS = plugin_opts; | 
			
		
	
		
			
				
					|  |  |  |         info->server_addr = SS_LOCAL_HOST; | 
			
		
	
		
			
				
					|  |  |  |         info->server_port = SS_LOCAL_PORT; | 
			
		
	
		
			
				
					|  |  |  |         SS_PLUGIN_OPTIONS = info->plugin_opts; | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     pack_shadowsocks_params(); | 
			
		
	
		
			
				
					|  |  |  |     shadowsocks_args = shadowsocks_opts; | 
			
		
	
		
			
				
					|  |  |  |     if (plugin == NULL) { | 
			
		
	
		
			
				
					|  |  |  |     pack_shadowsocks_params(info); | 
			
		
	
		
			
				
					|  |  |  |     shadowsocks_args = info->shadowsocks_opts; | 
			
		
	
		
			
				
					|  |  |  |     if (info->plugin == NULL) { | 
			
		
	
		
			
				
					|  |  |  |         plugin_file = NULL; | 
			
		
	
		
			
				
					|  |  |  |     } else { | 
			
		
	
		
			
				
					|  |  |  |         plugin_file = plugin; | 
			
		
	
		
			
				
					|  |  |  |         plugin_file = info->plugin; | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | void args_init() { // init arguments
 | 
			
		
	
		
			
				
					|  |  |  |     is_udp_proxy = 1; // udp proxy in default
 | 
			
		
	
		
			
				
					|  |  |  |     server_addr = client_addr = NULL; | 
			
		
	
		
			
				
					|  |  |  |     server_port = client_port = NULL; | 
			
		
	
		
			
				
					|  |  |  |     password = NULL; | 
			
		
	
		
			
				
					|  |  |  |     method = NULL; | 
			
		
	
		
			
				
					|  |  |  |     timeout = NULL; | 
			
		
	
		
			
				
					|  |  |  |     fastopen = 0; | 
			
		
	
		
			
				
					|  |  |  |     plugin = NULL; | 
			
		
	
		
			
				
					|  |  |  |     plugin_opts = NULL; | 
			
		
	
		
			
				
					|  |  |  |     shadowsocks = NULL; | 
			
		
	
		
			
				
					|  |  |  |     shadowsocks_opts = (char**)malloc(sizeof(char*) * 2); | 
			
		
	
		
			
				
					|  |  |  |     shadowsocks_opts[0] = ""; // reserved for program name
 | 
			
		
	
		
			
				
					|  |  |  |     shadowsocks_opts[1] = NULL; | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | //void args_init() { // init bootstrap arguments
 | 
			
		
	
		
			
				
					|  |  |  | //    is_udp_proxy = 1; // enable udp proxy in default
 | 
			
		
	
		
			
				
					|  |  |  | //    server_addr = client_addr = NULL;
 | 
			
		
	
		
			
				
					|  |  |  | //    server_port = client_port = NULL;
 | 
			
		
	
		
			
				
					|  |  |  | //    password = NULL;
 | 
			
		
	
		
			
				
					|  |  |  | //    method = NULL;
 | 
			
		
	
		
			
				
					|  |  |  | //    timeout = NULL;
 | 
			
		
	
		
			
				
					|  |  |  | //    fastopen = 0;
 | 
			
		
	
		
			
				
					|  |  |  | //    plugin = NULL;
 | 
			
		
	
		
			
				
					|  |  |  | //    plugin_opts = NULL;
 | 
			
		
	
		
			
				
					|  |  |  | //    shadowsocks = NULL;
 | 
			
		
	
		
			
				
					|  |  |  | //    shadowsocks_opts = (char**)malloc(sizeof(char*) * 2);
 | 
			
		
	
		
			
				
					|  |  |  | //    shadowsocks_opts[0] = ""; // reserved for program name
 | 
			
		
	
		
			
				
					|  |  |  | //    shadowsocks_opts[1] = NULL;
 | 
			
		
	
		
			
				
					|  |  |  | //}
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | char* read_file(char *file_name) { // read file content
 | 
			
		
	
		
			
				
					|  |  |  |     log_debug("Read file content -> %s", file_name); | 
			
		
	
		
			
				
					|  |  |  |     FILE *pfile = fopen(file_name, "rb"); | 
			
		
	
		
			
				
					|  |  |  |     if (pfile == NULL) { // open failed
 | 
			
		
	
		
			
				
					|  |  |  |         char *msg_prefix = "File `"; | 
			
		
	
		
			
				
					|  |  |  |         char *msg_suffix = "` open failed"; | 
			
		
	
		
			
				
					|  |  |  |         char *msg = (char*)malloc(strlen(msg_prefix) + strlen(file_name) + strlen(msg_suffix) + 1); | 
			
		
	
		
			
				
					|  |  |  |         strcpy(msg, msg_prefix); | 
			
		
	
		
			
				
					|  |  |  |         error_exit(strcat(strcat(msg, file_name), msg_suffix)); // merge error message
 | 
			
		
	
		
			
				
					|  |  |  |     if (pfile == NULL) { // file open failed
 | 
			
		
	
		
			
				
					|  |  |  |         log_fatal("File `%s` open failed", file_name); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     fseek(pfile, 0, SEEK_END); | 
			
		
	
		
			
				
					|  |  |  |     long file_length = ftell(pfile); // get file length
 | 
			
		
	
		
			
				
					|  |  |  |     char *file_content = (char*)malloc(file_length + 1); // malloc new memory
 | 
			
		
	
		
			
				
					|  |  |  |     if (file_content == NULL) { | 
			
		
	
		
			
				
					|  |  |  |         error_exit("no enough memory"); // file too large
 | 
			
		
	
		
			
				
					|  |  |  |         log_fatal("No enough memory for reading file"); // file too large
 | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     rewind(pfile); | 
			
		
	
		
			
				
					|  |  |  |     fread(file_content, 1, file_length, pfile); // read file stream
 | 
			
		
	
		
			
				
					|  |  |  |     file_content[file_length] = '\0'; // set end flag
 | 
			
		
	
		
			
				
					|  |  |  |     fclose(pfile); | 
			
		
	
		
			
				
					|  |  |  |     log_debug("File `%s` read success ->\n%s", file_name, file_content); | 
			
		
	
		
			
				
					|  |  |  |     return file_content; | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | void extra_options_decode(char *extra_opts) { // decode shadowsocks extra options
 | 
			
		
	
		
			
				
					|  |  |  | 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; | 
			
		
	
	
		
			
				
					|  |  | @ -119,7 +118,7 @@ void extra_options_decode(char *extra_opts) { // decode shadowsocks extra option | 
			
		
	
		
			
				
					|  |  |  |         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); | 
			
		
	
		
			
				
					|  |  |  |                 add_shadowsocks_option(tmp, opts); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             if (extra_opts[num] == '\0') { // string end
 | 
			
		
	
		
			
				
					|  |  |  |                 break; | 
			
		
	
	
		
			
				
					|  |  | @ -135,319 +134,334 @@ void extra_options_decode(char *extra_opts) { // decode shadowsocks extra option | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | void add_shadowsocks_option(char *option) { // add shadowsocks options
 | 
			
		
	
		
			
				
					|  |  |  | void add_shadowsocks_option(char *option, char **opts) { // add shadowsocks options
 | 
			
		
	
		
			
				
					|  |  |  |     int opt_num = 0; | 
			
		
	
		
			
				
					|  |  |  |     while(shadowsocks_opts[opt_num++] != NULL); // get options number
 | 
			
		
	
		
			
				
					|  |  |  |     shadowsocks_opts = (char**)realloc(shadowsocks_opts, sizeof(char**) * (opt_num + 1)); | 
			
		
	
		
			
				
					|  |  |  |     shadowsocks_opts[opt_num - 1] = strcpy((char*)malloc(strlen(option) + 1), option); | 
			
		
	
		
			
				
					|  |  |  |     shadowsocks_opts[opt_num] = NULL; // end sign
 | 
			
		
	
		
			
				
					|  |  |  |     while(opts[opt_num++] != NULL); // get options number
 | 
			
		
	
		
			
				
					|  |  |  |     opts = (char**)realloc(opts, sizeof(char**) * (opt_num + 1)); | 
			
		
	
		
			
				
					|  |  |  |     opts[opt_num - 1] = strcpy((char*)malloc(strlen(option) + 1), option); | 
			
		
	
		
			
				
					|  |  |  |     opts[opt_num] = NULL; // end sign
 | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | void pack_shadowsocks_params() { // packaging shadowsocks parameters
 | 
			
		
	
		
			
				
					|  |  |  |     if (server_addr != NULL) { | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option("-s"); | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option(server_addr); | 
			
		
	
		
			
				
					|  |  |  | void pack_shadowsocks_params(bootstrap_info *info) { // packaging shadowsocks parameters
 | 
			
		
	
		
			
				
					|  |  |  |     if (info->server_addr != NULL) { | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option("-s", info->shadowsocks_opts); | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option(info->server_addr, info->shadowsocks_opts); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     if (client_addr != NULL) { | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option("-b"); | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option(client_addr);  | 
			
		
	
		
			
				
					|  |  |  |     if (info->client_addr != NULL) { | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option("-b", info->shadowsocks_opts); | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option(info->client_addr, info->shadowsocks_opts); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     if (server_port != NULL) { | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option("-p"); | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option(server_port); | 
			
		
	
		
			
				
					|  |  |  |     if (info->server_port != NULL) { | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option("-p", info->shadowsocks_opts); | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option(info->server_port, info->shadowsocks_opts); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     if (client_port != NULL) { | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option("-l"); | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option(client_port); | 
			
		
	
		
			
				
					|  |  |  |     if (info->client_port != NULL) { | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option("-l", info->shadowsocks_opts); | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option(info->client_port, info->shadowsocks_opts); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     if (password != NULL) { | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option("-k"); | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option(password); | 
			
		
	
		
			
				
					|  |  |  |     if (info->password != NULL) { | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option("-k", info->shadowsocks_opts); | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option(info->password, info->shadowsocks_opts); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     if (method != NULL) { | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option("-m"); | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option(method); | 
			
		
	
		
			
				
					|  |  |  |     if (info->method != NULL) { | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option("-m", info->shadowsocks_opts); | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option(info->method, info->shadowsocks_opts); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     if (timeout != NULL) { | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option("-t"); | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option(timeout); | 
			
		
	
		
			
				
					|  |  |  |     if (info->timeout != NULL) { | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option("-t", info->shadowsocks_opts); | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option(info->timeout, info->shadowsocks_opts); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     if (fastopen) { | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option("--fast-open"); | 
			
		
	
		
			
				
					|  |  |  |     if (info->fastopen) { | 
			
		
	
		
			
				
					|  |  |  |         add_shadowsocks_option("--fast-open", info->shadowsocks_opts); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | void json_decode(char *json_content) { // decode JSON content
 | 
			
		
	
		
			
				
					|  |  |  | void json_decode(char *json_content, bootstrap_info *info) { // decode JSON content
 | 
			
		
	
		
			
				
					|  |  |  |     cJSON* json = NULL; | 
			
		
	
		
			
				
					|  |  |  |     json = cJSON_Parse(json_content); | 
			
		
	
		
			
				
					|  |  |  |     if (json == NULL) { | 
			
		
	
		
			
				
					|  |  |  |         error_exit("JSON format error.\n"); | 
			
		
	
		
			
				
					|  |  |  |         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)) { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`no_udp` must be a bool.\n"); | 
			
		
	
		
			
				
					|  |  |  |                 log_fatal("`no_udp` must be a bool."); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             if (json->valueint) { // is_udp_proxy = ~(json->valueint)
 | 
			
		
	
		
			
				
					|  |  |  |                 is_udp_proxy = 0; | 
			
		
	
		
			
				
					|  |  |  |                 info->is_udp_proxy = 0; | 
			
		
	
		
			
				
					|  |  |  |             } else { | 
			
		
	
		
			
				
					|  |  |  |                 is_udp_proxy = 1; | 
			
		
	
		
			
				
					|  |  |  |                 info->is_udp_proxy = 1; | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |         } else if (!strcmp(json->string, "server")) { // server => server_addr
 | 
			
		
	
		
			
				
					|  |  |  |             if (!cJSON_IsString(json)) { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`server` must be a string.\n"); | 
			
		
	
		
			
				
					|  |  |  |                 log_fatal("`server` must be a string."); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             if (server_addr != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(server_addr); | 
			
		
	
		
			
				
					|  |  |  |             if (info->server_addr != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(info->server_addr); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             server_addr = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring); | 
			
		
	
		
			
				
					|  |  |  |             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)) { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`local_address` must be a string.\n"); | 
			
		
	
		
			
				
					|  |  |  |                 log_fatal("`local_address` must be a string."); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             if (client_addr != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(client_addr); | 
			
		
	
		
			
				
					|  |  |  |             if (info->client_addr != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(info->client_addr); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             client_addr = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring); | 
			
		
	
		
			
				
					|  |  |  |             info->client_addr = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring); | 
			
		
	
		
			
				
					|  |  |  |         } else if (!strcmp(json->string, "server_port")) { // server_port => server_port
 | 
			
		
	
		
			
				
					|  |  |  |             if (server_port != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(server_port); | 
			
		
	
		
			
				
					|  |  |  |             if (info->server_port != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(info->server_port); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             if (cJSON_IsNumber(json)) { | 
			
		
	
		
			
				
					|  |  |  |                 server_port = int_to_string(json->valueint); | 
			
		
	
		
			
				
					|  |  |  |                 info->server_port = int_to_string(json->valueint); | 
			
		
	
		
			
				
					|  |  |  |             } else if (cJSON_IsString(json)) { | 
			
		
	
		
			
				
					|  |  |  |                 server_port = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring); | 
			
		
	
		
			
				
					|  |  |  |                 info->server_port = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring); | 
			
		
	
		
			
				
					|  |  |  |             } else { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`server_port` must be a number or string.\n"); | 
			
		
	
		
			
				
					|  |  |  |                 log_fatal("`server_port` must be a number or string."); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |         } else if (!strcmp(json->string, "local_port")) { // local_port => client_port
 | 
			
		
	
		
			
				
					|  |  |  |             if (client_port != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(client_port); | 
			
		
	
		
			
				
					|  |  |  |             if (info->client_port != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(info->client_port); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             if (cJSON_IsNumber(json)) { | 
			
		
	
		
			
				
					|  |  |  |                 client_port = int_to_string(json->valueint); | 
			
		
	
		
			
				
					|  |  |  |                 info->client_port = int_to_string(json->valueint); | 
			
		
	
		
			
				
					|  |  |  |             } else if (cJSON_IsString(json)) { | 
			
		
	
		
			
				
					|  |  |  |                 client_port = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring); | 
			
		
	
		
			
				
					|  |  |  |                 info->client_port = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring); | 
			
		
	
		
			
				
					|  |  |  |             } else { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`local_port` must be a number or string.\n"); | 
			
		
	
		
			
				
					|  |  |  |                 log_fatal("`local_port` must be a number or string."); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |         } else if (!strcmp(json->string, "password")) { // password => password
 | 
			
		
	
		
			
				
					|  |  |  |             if (!cJSON_IsString(json)) { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`password` must be a string.\n"); | 
			
		
	
		
			
				
					|  |  |  |                 log_fatal("`password` must be a string."); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             if (password != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(password); | 
			
		
	
		
			
				
					|  |  |  |             if (info->password != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(info->password); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             password = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring); | 
			
		
	
		
			
				
					|  |  |  |             info->password = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring); | 
			
		
	
		
			
				
					|  |  |  |         } else if (!strcmp(json->string, "timeout")) { // timeout => timeout
 | 
			
		
	
		
			
				
					|  |  |  |             if (timeout != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(timeout); | 
			
		
	
		
			
				
					|  |  |  |             if (info->timeout != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(info->timeout); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             if (cJSON_IsNumber(json)) { | 
			
		
	
		
			
				
					|  |  |  |                 timeout = int_to_string(json->valueint); | 
			
		
	
		
			
				
					|  |  |  |                 info->timeout = int_to_string(json->valueint); | 
			
		
	
		
			
				
					|  |  |  |             } else if (cJSON_IsString(json)) { | 
			
		
	
		
			
				
					|  |  |  |                 timeout = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring); | 
			
		
	
		
			
				
					|  |  |  |                 info->timeout = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring); | 
			
		
	
		
			
				
					|  |  |  |             } else { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`timeout` must be a number or string.\n"); | 
			
		
	
		
			
				
					|  |  |  |                 log_fatal("`timeout` must be a number or string."); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |         } else if (!strcmp(json->string, "method")) { // method => method
 | 
			
		
	
		
			
				
					|  |  |  |             if (!cJSON_IsString(json)) { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`method` must be a string.\n"); | 
			
		
	
		
			
				
					|  |  |  |                 log_fatal("`method` must be a string."); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             if (method != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(method); | 
			
		
	
		
			
				
					|  |  |  |             if (info->method != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(info->method); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             method = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring); | 
			
		
	
		
			
				
					|  |  |  |             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)) { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`fast_open` must be a bool.\n"); | 
			
		
	
		
			
				
					|  |  |  |                 log_fatal("`fast_open` must be a bool."); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             fastopen = json->valueint; | 
			
		
	
		
			
				
					|  |  |  |             info->fastopen = json->valueint; | 
			
		
	
		
			
				
					|  |  |  |         } else if (!strcmp(json->string, "plugin")) { // plugin => plugin
 | 
			
		
	
		
			
				
					|  |  |  |             if (!cJSON_IsString(json)) { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`plugin` must be a string.\n"); | 
			
		
	
		
			
				
					|  |  |  |                 log_fatal("`plugin` must be a string."); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             if (plugin != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(plugin); | 
			
		
	
		
			
				
					|  |  |  |             if (info->plugin != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(info->plugin); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             plugin = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring); | 
			
		
	
		
			
				
					|  |  |  |             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)) { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`plugin_opts` must be a string.\n"); | 
			
		
	
		
			
				
					|  |  |  |                 log_fatal("`plugin_opts` must be a string."); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             if (plugin_opts != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(plugin_opts); | 
			
		
	
		
			
				
					|  |  |  |             if (info->plugin_opts != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(info->plugin_opts); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             plugin_opts = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring); | 
			
		
	
		
			
				
					|  |  |  |             info->plugin_opts = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring); | 
			
		
	
		
			
				
					|  |  |  |         } else if (!strcmp(json->string, "shadowsocks")) { // shadowsocks => shadowsocks
 | 
			
		
	
		
			
				
					|  |  |  |             if (!cJSON_IsString(json)) { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`shadowsocks` must be a string.\n"); | 
			
		
	
		
			
				
					|  |  |  |                 log_fatal("`shadowsocks` must be a string."); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             if (shadowsocks != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(shadowsocks); | 
			
		
	
		
			
				
					|  |  |  |             if (info->shadowsocks != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(info->shadowsocks); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             shadowsocks = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring); | 
			
		
	
		
			
				
					|  |  |  |             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)) { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`extra_opts` must be a string.\n"); | 
			
		
	
		
			
				
					|  |  |  |                 log_fatal("`extra_opts` must be a string."); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             extra_options_decode(json->valuestring); | 
			
		
	
		
			
				
					|  |  |  |             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); | 
			
		
	
		
			
				
					|  |  |  |             error_exit(strcat(strcat(msg, json->string), msg_suffix)); | 
			
		
	
		
			
				
					|  |  |  |             log_fatal(strcat(strcat(msg, json->string), msg_suffix)); | 
			
		
	
		
			
				
					|  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |         json = json->next; // next field
 | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     cJSON_free(json); // free JSON struct
 | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | void args_decode(int argc, char **argv) { // decode the input parameters
 | 
			
		
	
		
			
				
					|  |  |  |     args_init(); | 
			
		
	
		
			
				
					|  |  |  |     int i; | 
			
		
	
		
			
				
					|  |  |  |     int debug_flag = 0; | 
			
		
	
		
			
				
					|  |  |  |     for (i = 1; i < argc; ++i) { | 
			
		
	
		
			
				
					|  |  |  |         if (!strcmp(argv[i], "--debug")) { // --debug => dump args
 | 
			
		
	
		
			
				
					|  |  |  |             debug_flag = 1; | 
			
		
	
		
			
				
					|  |  |  |         } else if (!strcmp(argv[i], "--no-udp")) { // --no-udp => without udp proxy
 | 
			
		
	
		
			
				
					|  |  |  |             is_udp_proxy = 0; | 
			
		
	
		
			
				
					|  |  |  |         } else if (!strcmp(argv[i], "-c")) { // -c => CONFIG_JSON
 | 
			
		
	
		
			
				
					|  |  |  |             if (i + 1 == argc) { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`-c` require a parameter"); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             json_decode(read_file(argv[++i])); | 
			
		
	
		
			
				
					|  |  |  |         } else if (!strcmp(argv[i], "-s")) { // -s => server_addr
 | 
			
		
	
		
			
				
					|  |  |  |             if (i + 1 == argc) { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`-s` require a parameter"); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             if (server_addr != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(server_addr); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             ++i; | 
			
		
	
		
			
				
					|  |  |  |             server_addr = strcpy((char*)malloc(strlen(argv[i]) + 1), argv[i]); | 
			
		
	
		
			
				
					|  |  |  |         } else if (!strcmp(argv[i], "-p")) { // -p => server_port
 | 
			
		
	
		
			
				
					|  |  |  |             if (i + 1 == argc) { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`-p` require a parameter"); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             if (server_port != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(server_port); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             ++i; | 
			
		
	
		
			
				
					|  |  |  |             server_port = strcpy((char*)malloc(strlen(argv[i]) + 1), argv[i]); | 
			
		
	
		
			
				
					|  |  |  |         } else if (!strcmp(argv[i], "-b")) { // -b => client_addr
 | 
			
		
	
		
			
				
					|  |  |  |             if (i + 1 == argc) { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`-b` require a parameter"); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             if (client_addr != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(client_addr); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             ++i; | 
			
		
	
		
			
				
					|  |  |  |             client_addr = strcpy((char*)malloc(strlen(argv[i]) + 1), argv[i]); | 
			
		
	
		
			
				
					|  |  |  |         } else if (!strcmp(argv[i], "-l")) { // -l => client_port
 | 
			
		
	
		
			
				
					|  |  |  |             if (i + 1 == argc) { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`-l` require a parameter"); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             if (client_port != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(client_port); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             ++i; | 
			
		
	
		
			
				
					|  |  |  |             client_port = strcpy((char*)malloc(strlen(argv[i]) + 1), argv[i]); | 
			
		
	
		
			
				
					|  |  |  |         } else if (!strcmp(argv[i], "-k")) { // -k => password
 | 
			
		
	
		
			
				
					|  |  |  |             if (i + 1 == argc) { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`-k` require a parameter"); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             if (password != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(password); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             ++i; | 
			
		
	
		
			
				
					|  |  |  |             password = strcpy((char*)malloc(strlen(argv[i]) + 1), argv[i]); | 
			
		
	
		
			
				
					|  |  |  |         } else if (!strcmp(argv[i], "-m")) { // -m => method
 | 
			
		
	
		
			
				
					|  |  |  |             if (i + 1 == argc) { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`-m` require a parameter"); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             if (method != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(method); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             ++i; | 
			
		
	
		
			
				
					|  |  |  |             method = strcpy((char*)malloc(strlen(argv[i]) + 1), argv[i]); | 
			
		
	
		
			
				
					|  |  |  |         } else if (!strcmp(argv[i], "-t")) { // -t => timeout
 | 
			
		
	
		
			
				
					|  |  |  |             if (i + 1 == argc) { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`-t` require a parameter"); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             if (timeout != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(timeout); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             ++i; | 
			
		
	
		
			
				
					|  |  |  |             timeout = strcpy((char*)malloc(strlen(argv[i]) + 1), argv[i]); | 
			
		
	
		
			
				
					|  |  |  |         } else if (!strcmp(argv[i], "--fast-open")) { // --fast-open
 | 
			
		
	
		
			
				
					|  |  |  |             fastopen = 1; | 
			
		
	
		
			
				
					|  |  |  |         } else if (!strcmp(argv[i], "--plugin")) { // --plugin => plugin
 | 
			
		
	
		
			
				
					|  |  |  |             if (i + 1 == argc) { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`--plugin` require a parameter"); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             if (plugin != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(plugin); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             ++i; | 
			
		
	
		
			
				
					|  |  |  |             plugin = strcpy((char*)malloc(strlen(argv[i]) + 1), argv[i]); | 
			
		
	
		
			
				
					|  |  |  |         } else if (!strcmp(argv[i], "--plugin-opts")) { // --plugin-opts => plugin_opts
 | 
			
		
	
		
			
				
					|  |  |  |             if (i + 1 == argc) { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`--plugin-opts` require a parameter"); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             if (plugin_opts != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(plugin_opts); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             ++i; | 
			
		
	
		
			
				
					|  |  |  |             plugin_opts = strcpy((char*)malloc(strlen(argv[i]) + 1), argv[i]); | 
			
		
	
		
			
				
					|  |  |  |         } else if (!strcmp(argv[i], "--shadowsocks")) { // --shadowsocks => shadowsocks
 | 
			
		
	
		
			
				
					|  |  |  |             if (i + 1 == argc) { | 
			
		
	
		
			
				
					|  |  |  |                 error_exit("`--shadowsocks` require a parameter"); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             if (shadowsocks != NULL) { | 
			
		
	
		
			
				
					|  |  |  |                 free(shadowsocks); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |             ++i; | 
			
		
	
		
			
				
					|  |  |  |             shadowsocks = strcpy((char*)malloc(strlen(argv[i]) + 1), argv[i]); | 
			
		
	
		
			
				
					|  |  |  |         } else { // unknown option => archive
 | 
			
		
	
		
			
				
					|  |  |  |             add_shadowsocks_option(argv[i]); // archive unknown options
 | 
			
		
	
		
			
				
					|  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     if (server_addr == NULL) { // default server address (bind address in server mode)
 | 
			
		
	
		
			
				
					|  |  |  |         server_addr = "127.0.0.1"; | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     if (debug_flag) { // show args for debug
 | 
			
		
	
		
			
				
					|  |  |  |         args_dump(); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 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); | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | void args_dump() { // show parameter's content
 | 
			
		
	
		
			
				
					|  |  |  |     if (is_udp_proxy) { | 
			
		
	
		
			
				
					|  |  |  |         printf("is_udp_proxy = true\n"); | 
			
		
	
		
			
				
					|  |  |  | void args_debug(bootstrap_info *info) { | 
			
		
	
		
			
				
					|  |  |  |     if (info->is_udp_proxy) { | 
			
		
	
		
			
				
					|  |  |  |         log_debug("is_udp_proxy = true"); | 
			
		
	
		
			
				
					|  |  |  |     } else { | 
			
		
	
		
			
				
					|  |  |  |         printf("is_udp_proxy = false\n"); | 
			
		
	
		
			
				
					|  |  |  |         log_debug("is_udp_proxy = false"); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     printf("server_addr = %s\n", server_addr); | 
			
		
	
		
			
				
					|  |  |  |     printf("client_addr = %s\n", client_addr); | 
			
		
	
		
			
				
					|  |  |  |     printf("server_port = %s\n", server_port); | 
			
		
	
		
			
				
					|  |  |  |     printf("client_port = %s\n", client_port); | 
			
		
	
		
			
				
					|  |  |  |     printf("password = %s\n", password); | 
			
		
	
		
			
				
					|  |  |  |     printf("method = %s\n", method); | 
			
		
	
		
			
				
					|  |  |  |     printf("timeout = %s\n", timeout); | 
			
		
	
		
			
				
					|  |  |  |     if (fastopen) { | 
			
		
	
		
			
				
					|  |  |  |     printf("server_addr = %s\n", info->server_addr); | 
			
		
	
		
			
				
					|  |  |  |     printf("client_addr = %s\n", info->client_addr); | 
			
		
	
		
			
				
					|  |  |  |     printf("server_port = %s\n", info->server_port); | 
			
		
	
		
			
				
					|  |  |  |     printf("client_port = %s\n", info->client_port); | 
			
		
	
		
			
				
					|  |  |  |     printf("password = %s\n", info->password); | 
			
		
	
		
			
				
					|  |  |  |     printf("method = %s\n", info->method); | 
			
		
	
		
			
				
					|  |  |  |     printf("timeout = %s\n", info->timeout); | 
			
		
	
		
			
				
					|  |  |  |     if (info->fastopen) { | 
			
		
	
		
			
				
					|  |  |  |         printf("fastopen = true\n"); | 
			
		
	
		
			
				
					|  |  |  |     } else { | 
			
		
	
		
			
				
					|  |  |  |         printf("fastopen = false\n"); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     printf("shadowsocks = %s\n", shadowsocks); | 
			
		
	
		
			
				
					|  |  |  |     printf("plugin = %s\n", plugin); | 
			
		
	
		
			
				
					|  |  |  |     printf("plugin_opts = %s\n", plugin_opts); | 
			
		
	
		
			
				
					|  |  |  |     printf("shadowsocks = %s\n", info->shadowsocks); | 
			
		
	
		
			
				
					|  |  |  |     printf("plugin = %s\n", info->plugin); | 
			
		
	
		
			
				
					|  |  |  |     printf("plugin_opts = %s\n", info->plugin_opts); | 
			
		
	
		
			
				
					|  |  |  |     int num = 0; | 
			
		
	
		
			
				
					|  |  |  |     printf("options:\n"); | 
			
		
	
		
			
				
					|  |  |  |     while(shadowsocks_opts[num] != NULL) { | 
			
		
	
		
			
				
					|  |  |  |         printf("  '%s'\n", shadowsocks_opts[num]); | 
			
		
	
		
			
				
					|  |  |  |     while(info->shadowsocks_opts[num] != NULL) { | 
			
		
	
		
			
				
					|  |  |  |         printf("  '%s'\n", info->shadowsocks_opts[num]); | 
			
		
	
		
			
				
					|  |  |  |         num++; | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 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
 | 
			
		
	
		
			
				
					|  |  |  | //
 | 
			
		
	
		
			
				
					|  |  |  | //}
 | 
			
		
	
	
		
			
				
					|  |  | 
 |