dnomd343
3 years ago
commit
e3c4f9f95f
10 changed files with 4198 additions and 0 deletions
File diff suppressed because it is too large
@ -0,0 +1,293 @@ |
|||
/*
|
|||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
of this software and associated documentation files (the "Software"), to deal |
|||
in the Software without restriction, including without limitation the rights |
|||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
copies of the Software, and to permit persons to whom the Software is |
|||
furnished to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in |
|||
all copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
THE SOFTWARE. |
|||
*/ |
|||
|
|||
#ifndef cJSON__h |
|||
#define cJSON__h |
|||
|
|||
#ifdef __cplusplus |
|||
extern "C" |
|||
{ |
|||
#endif |
|||
|
|||
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) |
|||
#define __WINDOWS__ |
|||
#endif |
|||
|
|||
#ifdef __WINDOWS__ |
|||
|
|||
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
|
|||
|
|||
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols |
|||
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) |
|||
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol |
|||
|
|||
For *nix builds that support visibility attribute, you can define similar behavior by |
|||
|
|||
setting default visibility to hidden by adding |
|||
-fvisibility=hidden (for gcc) |
|||
or |
|||
-xldscope=hidden (for sun cc) |
|||
to CFLAGS |
|||
|
|||
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does |
|||
|
|||
*/ |
|||
|
|||
#define CJSON_CDECL __cdecl |
|||
#define CJSON_STDCALL __stdcall |
|||
|
|||
/* export symbols by default, this is necessary for copy pasting the C and header file */ |
|||
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) |
|||
#define CJSON_EXPORT_SYMBOLS |
|||
#endif |
|||
|
|||
#if defined(CJSON_HIDE_SYMBOLS) |
|||
#define CJSON_PUBLIC(type) type CJSON_STDCALL |
|||
#elif defined(CJSON_EXPORT_SYMBOLS) |
|||
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL |
|||
#elif defined(CJSON_IMPORT_SYMBOLS) |
|||
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL |
|||
#endif |
|||
#else /* !__WINDOWS__ */ |
|||
#define CJSON_CDECL |
|||
#define CJSON_STDCALL |
|||
|
|||
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) |
|||
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type |
|||
#else |
|||
#define CJSON_PUBLIC(type) type |
|||
#endif |
|||
#endif |
|||
|
|||
/* project version */ |
|||
#define CJSON_VERSION_MAJOR 1 |
|||
#define CJSON_VERSION_MINOR 7 |
|||
#define CJSON_VERSION_PATCH 15 |
|||
|
|||
#include <stddef.h> |
|||
|
|||
/* cJSON Types: */ |
|||
#define cJSON_Invalid (0) |
|||
#define cJSON_False (1 << 0) |
|||
#define cJSON_True (1 << 1) |
|||
#define cJSON_NULL (1 << 2) |
|||
#define cJSON_Number (1 << 3) |
|||
#define cJSON_String (1 << 4) |
|||
#define cJSON_Array (1 << 5) |
|||
#define cJSON_Object (1 << 6) |
|||
#define cJSON_Raw (1 << 7) /* raw json */ |
|||
|
|||
#define cJSON_IsReference 256 |
|||
#define cJSON_StringIsConst 512 |
|||
|
|||
/* The cJSON structure: */ |
|||
typedef struct cJSON |
|||
{ |
|||
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ |
|||
struct cJSON *next; |
|||
struct cJSON *prev; |
|||
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ |
|||
struct cJSON *child; |
|||
|
|||
/* The type of the item, as above. */ |
|||
int type; |
|||
|
|||
/* The item's string, if type==cJSON_String and type == cJSON_Raw */ |
|||
char *valuestring; |
|||
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ |
|||
int valueint; |
|||
/* The item's number, if type==cJSON_Number */ |
|||
double valuedouble; |
|||
|
|||
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ |
|||
char *string; |
|||
} cJSON; |
|||
|
|||
typedef struct cJSON_Hooks |
|||
{ |
|||
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ |
|||
void *(CJSON_CDECL *malloc_fn)(size_t sz); |
|||
void (CJSON_CDECL *free_fn)(void *ptr); |
|||
} cJSON_Hooks; |
|||
|
|||
typedef int cJSON_bool; |
|||
|
|||
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
|
|||
* This is to prevent stack overflows. */ |
|||
#ifndef CJSON_NESTING_LIMIT |
|||
#define CJSON_NESTING_LIMIT 1000 |
|||
#endif |
|||
|
|||
/* returns the version of cJSON as a string */ |
|||
CJSON_PUBLIC(const char*) cJSON_Version(void); |
|||
|
|||
/* Supply malloc, realloc and free functions to cJSON */ |
|||
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); |
|||
|
|||
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ |
|||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ |
|||
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); |
|||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length); |
|||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ |
|||
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ |
|||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); |
|||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated); |
|||
|
|||
/* Render a cJSON entity to text for transfer/storage. */ |
|||
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); |
|||
/* Render a cJSON entity to text for transfer/storage without any formatting. */ |
|||
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); |
|||
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ |
|||
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); |
|||
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ |
|||
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); |
|||
/* Delete a cJSON entity and all subentities. */ |
|||
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); |
|||
|
|||
/* Returns the number of items in an array (or object). */ |
|||
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); |
|||
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ |
|||
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); |
|||
/* Get item "string" from object. Case insensitive. */ |
|||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); |
|||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); |
|||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ |
|||
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); |
|||
|
|||
/* Check item type and return its value */ |
|||
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); |
|||
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item); |
|||
|
|||
/* These functions check the type of an item */ |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); |
|||
|
|||
/* These calls create a cJSON item of the appropriate type. */ |
|||
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); |
|||
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); |
|||
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); |
|||
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); |
|||
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); |
|||
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); |
|||
/* raw json */ |
|||
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); |
|||
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); |
|||
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); |
|||
|
|||
/* Create a string where valuestring references a string so
|
|||
* it will not be freed by cJSON_Delete */ |
|||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); |
|||
/* Create an object/array that only references it's elements so
|
|||
* they will not be freed by cJSON_Delete */ |
|||
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); |
|||
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); |
|||
|
|||
/* These utilities create an Array of count items.
|
|||
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/ |
|||
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); |
|||
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); |
|||
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); |
|||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count); |
|||
|
|||
/* Append item to the specified array/object. */ |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item); |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); |
|||
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
|
|||
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before |
|||
* writing to `item->string` */ |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); |
|||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); |
|||
|
|||
/* Remove/Detach items from Arrays/Objects. */ |
|||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); |
|||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); |
|||
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); |
|||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); |
|||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); |
|||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); |
|||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); |
|||
|
|||
/* Update array items. */ |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); |
|||
|
|||
/* Duplicate a cJSON item */ |
|||
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); |
|||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
|||
* need to be released. With recurse!=0, it will duplicate any children connected to the item. |
|||
* The item->next and ->prev pointers are always zero on return from Duplicate. */ |
|||
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
|
|||
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ |
|||
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); |
|||
|
|||
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
|
|||
* The input pointer json cannot point to a read-only address area, such as a string constant, |
|||
* but should point to a readable and writable address area. */ |
|||
CJSON_PUBLIC(void) cJSON_Minify(char *json); |
|||
|
|||
/* Helper functions for creating and adding items to an object at the same time.
|
|||
* They return the added item or NULL on failure. */ |
|||
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); |
|||
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); |
|||
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); |
|||
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); |
|||
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); |
|||
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); |
|||
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); |
|||
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); |
|||
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); |
|||
|
|||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */ |
|||
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) |
|||
/* helper for the cJSON_SetNumberValue macro */ |
|||
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); |
|||
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) |
|||
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */ |
|||
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring); |
|||
|
|||
/* Macro for iterating over an array or object */ |
|||
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) |
|||
|
|||
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ |
|||
CJSON_PUBLIC(void *) cJSON_malloc(size_t size); |
|||
CJSON_PUBLIC(void) cJSON_free(void *object); |
|||
|
|||
#ifdef __cplusplus |
|||
} |
|||
#endif |
|||
|
|||
#endif |
@ -0,0 +1,419 @@ |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include "cJSON.h" |
|||
#include "common.h" |
|||
#include "network.h" |
|||
#include "process.h" |
|||
|
|||
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; |
|||
|
|||
void args_dump(); |
|||
void args_init(); |
|||
void error_exit(char *msg); |
|||
char* int_to_string(int num); |
|||
void pack_shadowsocks_params(); |
|||
char* read_file(char *file_name); |
|||
void params_load(char *ss_default); |
|||
void json_decode(char *json_content); |
|||
void args_decode(int argc, char **argv); |
|||
void add_shadowsocks_option(char *option); |
|||
void extra_options_decode(char *extra_opts); |
|||
|
|||
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"); |
|||
} |
|||
int count = 0; |
|||
int temp = num; |
|||
while(temp != 0) { // check the number of digits
|
|||
temp /= 10; |
|||
++count; |
|||
} |
|||
char *str = (char*)malloc(count + 1); |
|||
sprintf(str, "%d", num); |
|||
return str; |
|||
} |
|||
|
|||
void params_load(char *ss_default) { // load shadowsocks and plugin params
|
|||
if (shadowsocks == NULL) { |
|||
shadowsocks = ss_default; |
|||
} |
|||
shadowsocks_opts[0] = shadowsocks; // fill with file name
|
|||
if (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_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; |
|||
} |
|||
pack_shadowsocks_params(); |
|||
shadowsocks_file = shadowsocks; |
|||
shadowsocks_args = shadowsocks_opts; |
|||
if (plugin == NULL) { |
|||
plugin_file = NULL; |
|||
} else { |
|||
plugin_file = plugin; |
|||
} |
|||
} |
|||
|
|||
void args_init() { // init arguments
|
|||
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
|
|||
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
|
|||
} |
|||
fseek(pfile, 0, SEEK_END); |
|||
int 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
|
|||
} |
|||
rewind(pfile); |
|||
fread(file_content, 1, file_length, pfile); // read file stream
|
|||
file_content[file_length] = '\0'; // set end flag
|
|||
fclose(pfile); |
|||
return file_content; |
|||
} |
|||
|
|||
void extra_options_decode(char *extra_opts) { // decode shadowsocks extra options
|
|||
int num, i; |
|||
char *tmp = (char*)calloc(strlen(extra_opts) + 1, 1); // new memery 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); |
|||
} |
|||
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) { // 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
|
|||
} |
|||
|
|||
void pack_shadowsocks_params() { // packaging shadowsocks parameters
|
|||
if (server_addr != NULL) { |
|||
add_shadowsocks_option("-s"); |
|||
add_shadowsocks_option(server_addr); |
|||
} |
|||
if (client_addr != NULL) { |
|||
add_shadowsocks_option("-b"); |
|||
add_shadowsocks_option(client_addr); |
|||
} |
|||
if (server_port != NULL) { |
|||
add_shadowsocks_option("-p"); |
|||
add_shadowsocks_option(server_port); |
|||
} |
|||
if (client_port != NULL) { |
|||
add_shadowsocks_option("-l"); |
|||
add_shadowsocks_option(client_port); |
|||
} |
|||
if (password != NULL) { |
|||
add_shadowsocks_option("-k"); |
|||
add_shadowsocks_option(password); |
|||
} |
|||
if (method != NULL) { |
|||
add_shadowsocks_option("-m"); |
|||
add_shadowsocks_option(method); |
|||
} |
|||
if (timeout != NULL) { |
|||
add_shadowsocks_option("-t"); |
|||
add_shadowsocks_option(timeout); |
|||
} |
|||
if (fastopen) { |
|||
add_shadowsocks_option("--fast-open"); |
|||
} |
|||
} |
|||
|
|||
void json_decode(char *json_content) { // decode JSON content
|
|||
cJSON* json = NULL; |
|||
json = cJSON_Parse(json_content); |
|||
if (json == NULL) { |
|||
error_exit("JSON format error.\n"); |
|||
} |
|||
json = json->child; |
|||
while (json != NULL) { |
|||
if (!strcmp(json->string, "server")) { // server => server_addr
|
|||
if (!cJSON_IsString(json)) { |
|||
error_exit("`server` must be a string.\n"); |
|||
} |
|||
if (server_addr != NULL) { |
|||
free(server_addr); |
|||
} |
|||
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"); |
|||
} |
|||
if (client_addr != NULL) { |
|||
free(client_addr); |
|||
} |
|||
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 (cJSON_IsNumber(json)) { |
|||
server_port = int_to_string(json->valueint); |
|||
} else if (cJSON_IsString(json)) { |
|||
server_port = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring); |
|||
} else { |
|||
error_exit("`server_port` must be a number or string.\n"); |
|||
} |
|||
} else if (!strcmp(json->string, "local_port")) { // local_port => client_port
|
|||
if (client_port != NULL) { |
|||
free(client_port); |
|||
} |
|||
if (cJSON_IsNumber(json)) { |
|||
client_port = int_to_string(json->valueint); |
|||
} else if (cJSON_IsString(json)) { |
|||
client_port = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring); |
|||
} else { |
|||
error_exit("`local_port` must be a number or string.\n"); |
|||
} |
|||
} else if (!strcmp(json->string, "password")) { // password => password
|
|||
if (!cJSON_IsString(json)) { |
|||
error_exit("`password` must be a string.\n"); |
|||
} |
|||
if (password != NULL) { |
|||
free(password); |
|||
} |
|||
password = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring); |
|||
} else if (!strcmp(json->string, "timeout")) { // timeout => timeout
|
|||
if (timeout != NULL) { |
|||
free(timeout); |
|||
} |
|||
if (cJSON_IsNumber(json)) { |
|||
timeout = int_to_string(json->valueint); |
|||
} else if (cJSON_IsString(json)) { |
|||
timeout = strcpy((char*)malloc(strlen(json->valuestring) + 1), json->valuestring); |
|||
} else { |
|||
error_exit("`timeout` must be a number or string.\n"); |
|||
} |
|||
} else if (!strcmp(json->string, "method")) { // method => method
|
|||
if (!cJSON_IsString(json)) { |
|||
error_exit("`method` must be a string.\n"); |
|||
} |
|||
if (method != NULL) { |
|||
free(method); |
|||
} |
|||
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"); |
|||
} |
|||
fastopen = json->valueint; |
|||
} else if (!strcmp(json->string, "plugin")) { // plugin => plugin
|
|||
if (!cJSON_IsString(json)) { |
|||
error_exit("`plugin` must be a string.\n"); |
|||
} |
|||
if (plugin != NULL) { |
|||
free(plugin); |
|||
} |
|||
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"); |
|||
} |
|||
if (plugin_opts != NULL) { |
|||
free(plugin_opts); |
|||
} |
|||
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"); |
|||
} |
|||
if (shadowsocks != NULL) { |
|||
free(shadowsocks); |
|||
} |
|||
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"); |
|||
} |
|||
extra_options_decode(json->valuestring); |
|||
} else { // unknow field => ERROR
|
|||
char *msg_prefix = "Unknow 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)); |
|||
} |
|||
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; |
|||
for (i = 1; i < argc; ++i) { |
|||
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); |
|||
} |
|||
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); |
|||
} |
|||
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); |
|||
} |
|||
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); |
|||
} |
|||
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); |
|||
} |
|||
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); |
|||
} |
|||
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); |
|||
} |
|||
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); |
|||
} |
|||
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); |
|||
} |
|||
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); |
|||
} |
|||
shadowsocks = strcpy((char*)malloc(strlen(argv[i]) + 1), argv[++i]); |
|||
} else { // unknow option => archive
|
|||
add_shadowsocks_option(argv[i]); // archive unknow options
|
|||
} |
|||
} |
|||
} |
|||
|
|||
void args_dump() { // show parameter's content
|
|||
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("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); |
|||
int num = 0; |
|||
printf("options:\n"); |
|||
while(shadowsocks_opts[num] != NULL) { |
|||
printf(" '%s'\n", shadowsocks_opts[num]); |
|||
num++; |
|||
} |
|||
} |
@ -0,0 +1,21 @@ |
|||
#ifndef _COMMON_H_ |
|||
#define _COMMON_H_ |
|||
|
|||
#define RANDOM_PORT_START 41952 |
|||
#define RANDOM_PORT_END 65535 |
|||
|
|||
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; |
|||
|
|||
void params_load(char *ss_default); |
|||
void args_decode(int argc, char **argv); |
|||
|
|||
#endif |
@ -0,0 +1,44 @@ |
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
#include "common.h" |
|||
#include "process.h" |
|||
|
|||
#define SHADOWSOCKS_DEFAULT "sslocal" |
|||
|
|||
char *help_msg = |
|||
"\
|
|||
\n\ |
|||
ss-bootstrap-local\n\ |
|||
\n\ |
|||
A simple program to make the original shadowsocks support SIP003 plugins.\n\ |
|||
\n\ |
|||
-s <server_host> Host name or IP address of your remote server.\n\ |
|||
-p <server_port> Port number of your remote server.\n\ |
|||
-b <local_address> Local address to bind.\n\ |
|||
-l <local_port> Port number of your local server.\n\ |
|||
\n\ |
|||
-c <config_file> Path to JSON config file.\n\ |
|||
-k <password> Password of your remote server.\n\ |
|||
-m <method> Encrypt method.\n\ |
|||
-t <timeout> Socket timeout in seconds.\n\ |
|||
--fast-open Enable TCP fast open (with Linux kernel 3.7+).\n\ |
|||
--plugin <name> Enable SIP003 plugin.\n\ |
|||
--plugin-opts <options> Set SIP003 plugin options.\n\ |
|||
--shadowsocks <sslocal> Set shadowsocks local program.\n\ |
|||
-h, --help Print this message.\n\ |
|||
\n\ |
|||
"; |
|||
|
|||
int main(int argc, char *argv[]) { |
|||
int i = 0; |
|||
for (i = 0; i < argc; ++i) { |
|||
if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { |
|||
printf("%s", help_msg); // show help message
|
|||
return 0; |
|||
} |
|||
} |
|||
args_decode(argc, argv); |
|||
params_load(SHADOWSOCKS_DEFAULT); // default file name
|
|||
start_bootstrap(); |
|||
return 0; |
|||
} |
@ -0,0 +1,42 @@ |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <unistd.h> |
|||
#include <sys/time.h> |
|||
#include <netinet/in.h> |
|||
#include "network.h" |
|||
|
|||
int get_random_num(int range_start, int range_end) { // create a random number in range
|
|||
struct timeval tp; |
|||
gettimeofday(&tp, NULL); |
|||
srand(tp.tv_usec); |
|||
return range_start + (rand() % (range_end - range_start + 1)); |
|||
} |
|||
|
|||
int check_port_available(unsigned short port) { // test a port is available or not
|
|||
struct sockaddr_in server_addr; |
|||
memset(&server_addr, 0, sizeof(server_addr)); // struct init
|
|||
server_addr.sin_family = AF_INET; // set as IP communication
|
|||
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // allow any connection
|
|||
server_addr.sin_port = htons(port); // set telnet port
|
|||
int server_sockfd = socket(AF_INET, SOCK_STREAM, 0); // socket created
|
|||
if (server_sockfd < 0) { // create failed
|
|||
return 0; |
|||
} |
|||
if (bind(server_sockfd, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)) < 0) { // bind failed
|
|||
return 0; |
|||
} |
|||
if (close(server_sockfd) != 0) { // close failed
|
|||
return 0; |
|||
} |
|||
return 1; // port available
|
|||
} |
|||
|
|||
int get_available_port(unsigned short range_start, unsigned short range_end) { // get a available port
|
|||
unsigned short port; |
|||
for (;;) { // wait until a available port in range
|
|||
port = get_random_num(range_start, range_end); // get a random port in range
|
|||
if (check_port_available(port)) { // port available
|
|||
return (int)port; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,6 @@ |
|||
#ifndef _NETWORK_H_ |
|||
#define _NETWORK_H_ |
|||
|
|||
int get_available_port(unsigned short range_start, unsigned short range_end); |
|||
|
|||
#endif |
@ -0,0 +1,204 @@ |
|||
#include <glib.h> |
|||
#include <stdio.h> |
|||
#include <unistd.h> |
|||
#include <sys/wait.h> |
|||
#include <sys/prctl.h> |
|||
#include "process.h" |
|||
|
|||
char *shadowsocks_file; |
|||
char **shadowsocks_args; |
|||
char *plugin_file; |
|||
char *SS_REMOTE_HOST; |
|||
char *SS_REMOTE_PORT; |
|||
char *SS_LOCAL_HOST; |
|||
char *SS_LOCAL_PORT; |
|||
char *SS_PLUGIN_OPTIONS; |
|||
|
|||
char **plugin_env; |
|||
char *plugin_arg[] = { NULL, NULL }; |
|||
|
|||
int exiting = 0; |
|||
|
|||
typedef struct exit_info { |
|||
int pid; |
|||
int exit_code; |
|||
int exit_signal; |
|||
} exit_info; |
|||
|
|||
GMainLoop* main_loop; |
|||
pid_t ss_pid = 0, plugin_pid = 0; |
|||
|
|||
void show_params(); |
|||
void process_exec(); |
|||
void get_sub_exit(); |
|||
void exit_with_child(); |
|||
void plugin_env_load(); |
|||
void show_exit_info(exit_info info); |
|||
exit_info get_exit_info(int status, pid_t pid); |
|||
|
|||
void show_exit_info(exit_info info) { // show info of child process death
|
|||
printf("(PID = %d) -> ", info.pid); |
|||
if (info.exit_code != -1) { // exit normally
|
|||
printf("exit code %d.\n", info.exit_code); |
|||
} else if (info.exit_signal != -1) { // abnormal exit
|
|||
printf("killed by signal %d.\n", info.exit_signal); |
|||
} else { |
|||
printf("unknow reason.\n"); |
|||
} |
|||
} |
|||
|
|||
exit_info get_exit_info(int status, pid_t pid) { // get why the child process death
|
|||
exit_info temp; |
|||
temp.pid = pid; |
|||
temp.exit_code = temp.exit_signal = -1; |
|||
if (WIFEXITED(status)) { // exit normally (with a exit-code)
|
|||
temp.exit_code = WEXITSTATUS(status); |
|||
} |
|||
if (WIFSIGNALED(status)) { // abnormal exit (with a signal)
|
|||
temp.exit_signal = WTERMSIG(status); |
|||
} |
|||
return temp; |
|||
} |
|||
|
|||
void get_sub_exit() { // catch child process die
|
|||
exit_info sub_exit_info; |
|||
int ss_ret, plugin_ret, ss_status, plugin_status; |
|||
if (exiting) { |
|||
int status; |
|||
waitpid(0, &status, 0); |
|||
return; |
|||
} |
|||
if (ss_pid != 0) { |
|||
ss_ret = waitpid(ss_pid, &ss_status, WNOHANG); // non-blocking
|
|||
if (ss_ret == -1) { |
|||
perror("[Shadowsocks Bootstrap] shadowsocks waitpid error"); |
|||
exit_with_child(); |
|||
} else if (ss_ret) { // ss exit
|
|||
sub_exit_info = get_exit_info(ss_status, ss_pid); |
|||
printf("[Shadowsocks Bootstrap] shadowsocks exit "); |
|||
show_exit_info(sub_exit_info); |
|||
exit_with_child(); |
|||
} |
|||
} |
|||
if (plugin_file != NULL && plugin_pid != 0) { // with plugin
|
|||
plugin_ret = waitpid(plugin_pid, &plugin_status, WNOHANG); // non-blocking
|
|||
if (plugin_ret == -1) { |
|||
perror("[Shadowsocks Bootstrap] plugin waitpid error"); |
|||
exit_with_child(); |
|||
} else if (plugin_ret) { // plugin exit
|
|||
sub_exit_info = get_exit_info(plugin_status, plugin_pid); |
|||
printf("[Shadowsocks Bootstrap] plugin exit "); |
|||
show_exit_info(sub_exit_info); |
|||
exit_with_child(); |
|||
} |
|||
} |
|||
g_main_loop_quit(main_loop); // exit main loop
|
|||
} |
|||
|
|||
void plugin_env_load() { // load plugin's environment variable
|
|||
char *remote_host = "SS_REMOTE_HOST="; |
|||
char *remote_port = "SS_REMOTE_PORT="; |
|||
char *local_host = "SS_LOCAL_HOST="; |
|||
char *local_port = "SS_LOCAL_PORT="; |
|||
char *plugin_options = "SS_PLUGIN_OPTIONS="; |
|||
plugin_env = (char**)malloc(sizeof(char*) * 6); |
|||
plugin_env[0] = (char*)malloc(strlen(remote_host) + strlen(SS_REMOTE_HOST) + 1); |
|||
plugin_env[1] = (char*)malloc(strlen(remote_port) + strlen(SS_REMOTE_PORT) + 1); |
|||
plugin_env[2] = (char*)malloc(strlen(local_host) + strlen(SS_LOCAL_HOST) + 1); |
|||
plugin_env[3] = (char*)malloc(strlen(local_port) + strlen(SS_LOCAL_PORT) + 1); |
|||
strcat(strcpy(plugin_env[0], remote_host), SS_REMOTE_HOST); |
|||
strcat(strcpy(plugin_env[1], remote_port), SS_REMOTE_PORT); |
|||
strcat(strcpy(plugin_env[2], local_host), SS_LOCAL_HOST); |
|||
strcat(strcpy(plugin_env[3], local_port), SS_LOCAL_PORT); |
|||
if (SS_PLUGIN_OPTIONS == NULL) { |
|||
plugin_env[4] = NULL; |
|||
} else { |
|||
plugin_env[4] = (char*)malloc(strlen(plugin_options) + strlen(SS_PLUGIN_OPTIONS) + 1); |
|||
strcat(strcpy(plugin_env[4], plugin_options), SS_PLUGIN_OPTIONS); |
|||
} |
|||
plugin_env[5] = NULL; |
|||
plugin_arg[0] = plugin_file; |
|||
} |
|||
|
|||
void process_exec() { // run shadowsocks main process and plugin (as child process)
|
|||
if ((ss_pid = fork()) < 0) { |
|||
perror("[Shadowsocks Bootstrap] fork error"); |
|||
exit_with_child(); |
|||
} else if (ss_pid == 0) { // child process
|
|||
prctl(PR_SET_PDEATHSIG, SIGKILL); // child die with his father
|
|||
if (execvp(shadowsocks_args[0], shadowsocks_args) < 0) { |
|||
perror("[Shadowsocks Bootstrap] shadowsocks exec error"); |
|||
exit(2); |
|||
} |
|||
} |
|||
if (plugin_file == NULL) { // plugin no need
|
|||
return; |
|||
} |
|||
usleep(100 * 1000); // sleep 100ms (python always a little slower)
|
|||
if (exiting) { // cancel plugin exec
|
|||
return; |
|||
} |
|||
if ((plugin_pid = fork()) < 0) { |
|||
perror("[Shadowsocks Bootstrap] fork error"); |
|||
exit_with_child(); |
|||
} else if (plugin_pid == 0) { // child process
|
|||
prctl(PR_SET_PDEATHSIG, SIGKILL); // child die with his father
|
|||
plugin_env_load(); |
|||
if (execvpe(plugin_file, plugin_arg, plugin_env) < 0) { |
|||
perror("[Shadowsocks Bootstrap] plugin exec error"); |
|||
exit(2); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void exit_with_child() { // exit and kill his child process
|
|||
if (exiting) { |
|||
for (;;) { |
|||
sleep(1); // block
|
|||
} |
|||
} |
|||
exiting = 1; |
|||
if (ss_pid != 0) { |
|||
kill(ss_pid, SIGKILL); |
|||
printf("[Shadowsocks Bootstrap] kill shadowsocks process.\n"); |
|||
} |
|||
if (plugin_file != NULL && plugin_pid != 0) { |
|||
kill(plugin_pid, SIGKILL); |
|||
printf("[Shadowsocks Bootstrap] kill plugin process.\n"); |
|||
} |
|||
int status; |
|||
printf("[Shadowsocks Bootstrap] wait for child process.\n"); |
|||
waitpid(0, &status, 0); // block
|
|||
printf("[Shadowsocks Bootstrap] exit.\n"); |
|||
exit(1); |
|||
} |
|||
|
|||
void show_params() { // show shadowsocks and plugin params
|
|||
int num = 0; |
|||
printf("[Shadowsocks Bootstrap]"); |
|||
while(shadowsocks_args[num] != NULL) { |
|||
printf(" %s", shadowsocks_args[num++]); |
|||
} |
|||
printf("\n"); |
|||
if (plugin_file == NULL) { |
|||
printf("[Shadowsocks Bootstrap] plugin no need.\n"); |
|||
return; |
|||
} |
|||
printf("[Shadowsocks Bootstrap] plugin -> %s\n", plugin_file); |
|||
printf("[Shadowsocks Bootstrap] SS_REMOTE_HOST -> %s\n", SS_REMOTE_HOST); |
|||
printf("[Shadowsocks Bootstrap] SS_REMOTE_PORT -> %s\n", SS_REMOTE_PORT); |
|||
printf("[Shadowsocks Bootstrap] SS_LOCAL_HOST -> %s\n", SS_LOCAL_HOST); |
|||
printf("[Shadowsocks Bootstrap] SS_LOCAL_PORT -> %s\n", SS_LOCAL_PORT); |
|||
printf("[Shadowsocks Bootstrap] SS_PLUGIN_OPTIONS -> %s\n", SS_PLUGIN_OPTIONS); |
|||
} |
|||
|
|||
void start_bootstrap() { // start shadowsocks and plugin (optional)
|
|||
show_params(); |
|||
main_loop = g_main_loop_new(NULL, FALSE); |
|||
signal(SIGINT, exit_with_child); // catch Ctrl + C (2)
|
|||
signal(SIGTERM, exit_with_child); // catch exit signal (15)
|
|||
signal(SIGCHLD, get_sub_exit); // callback when child process die
|
|||
process_exec(); // exec child process
|
|||
g_main_loop_run(main_loop); // into main loop for wait
|
|||
exit_with_child(); |
|||
} |
@ -0,0 +1,15 @@ |
|||
#ifndef _PROCESS_H_ |
|||
#define _PROCESS_H_ |
|||
|
|||
extern char *shadowsocks_file; |
|||
extern char **shadowsocks_args; |
|||
extern char *plugin_file; |
|||
extern char *SS_REMOTE_HOST; |
|||
extern char *SS_REMOTE_PORT; |
|||
extern char *SS_LOCAL_HOST; |
|||
extern char *SS_LOCAL_PORT; |
|||
extern char *SS_PLUGIN_OPTIONS; |
|||
|
|||
void start_bootstrap(); |
|||
|
|||
#endif |
@ -0,0 +1,44 @@ |
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
#include "common.h" |
|||
#include "process.h" |
|||
|
|||
#define SHADOWSOCKS_DEFAULT "ssserver" |
|||
|
|||
char *help_msg = |
|||
"\
|
|||
\n\ |
|||
ss-bootstrap-server\n\ |
|||
\n\ |
|||
A simple program to make the original shadowsocks support SIP003 plugins.\n\ |
|||
\n\ |
|||
-s <server_host> Host name or IP address of your remote server.\n\ |
|||
-p <server_port> Port number of your remote server.\n\ |
|||
-b <local_address> Local address to bind.\n\ |
|||
-l <local_port> Port number of your local server.\n\ |
|||
\n\ |
|||
-c <config_file> Path to JSON config file.\n\ |
|||
-k <password> Password of your remote server.\n\ |
|||
-m <method> Encrypt method.\n\ |
|||
-t <timeout> Socket timeout in seconds.\n\ |
|||
--fast-open Enable TCP fast open (with Linux kernel 3.7+).\n\ |
|||
--plugin <name> Enable SIP003 plugin.\n\ |
|||
--plugin-opts <options> Set SIP003 plugin options.\n\ |
|||
--shadowsocks <ssservre> Set shadowsocks server program.\n\ |
|||
-h, --help Print this message.\n\ |
|||
\n\ |
|||
"; |
|||
|
|||
int main(int argc, char *argv[]) { |
|||
int i = 0; |
|||
for (i = 0; i < argc; ++i) { |
|||
if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { |
|||
printf("%s", help_msg); // show help message
|
|||
return 0; |
|||
} |
|||
} |
|||
args_decode(argc, argv); |
|||
params_load(SHADOWSOCKS_DEFAULT); // default file name
|
|||
start_bootstrap(); |
|||
return 0; |
|||
} |
Loading…
Reference in new issue