Max Lv
11 years ago
13 changed files with 1342 additions and 95 deletions
Unified View
Diff Options
-
4Makefile.am
-
11Makefile.in
-
3configure
-
3configure.ac
-
11encrypt.h
-
120jconf.c
-
19jconf.h
-
838json.c
-
222json.h
-
125local.c
-
3local.h
-
67utils.c
-
11utils.h
@ -1,4 +1,4 @@ |
|||||
bin_PROGRAMS = ss |
bin_PROGRAMS = ss |
||||
ss_SOURCES = rc4.c rc4.h md5.c md5.h encrypt.c encrypt.h local.c local.h socks5.h |
|
||||
AM_CFLAGS = -Wall -fno-strict-aliasing |
|
||||
|
ss_SOURCES = utils.c jconf.c json.c rc4.c rc4.h md5.c md5.h encrypt.c encrypt.h local.c local.h socks5.h |
||||
|
AM_CFLAGS = -O2 -Wall -fno-strict-aliasing |
||||
ACLOCAL_AMFLAGS = -I m4 |
ACLOCAL_AMFLAGS = -I m4 |
@ -0,0 +1,120 @@ |
|||||
|
#include <stdlib.h> |
||||
|
#include <stdio.h> |
||||
|
#include <unistd.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
#include "utils.h" |
||||
|
#include "jconf.h" |
||||
|
#include "json.h" |
||||
|
#include "string.h" |
||||
|
|
||||
|
#define INT_DIGITS 19 /* enough for 64 bit integer */ |
||||
|
|
||||
|
static char *itoa(int i) |
||||
|
{ |
||||
|
/* Room for INT_DIGITS digits, - and '\0' */ |
||||
|
static char buf[INT_DIGITS + 2]; |
||||
|
char *p = buf + INT_DIGITS + 1; /* points to terminating '\0' */ |
||||
|
if (i >= 0) { |
||||
|
do { |
||||
|
*--p = '0' + (i % 10); |
||||
|
i /= 10; |
||||
|
} while (i != 0); |
||||
|
return p; |
||||
|
} |
||||
|
else { /* i < 0 */ |
||||
|
do { |
||||
|
*--p = '0' - (i % 10); |
||||
|
i /= 10; |
||||
|
} while (i != 0); |
||||
|
*--p = '-'; |
||||
|
} |
||||
|
return p; |
||||
|
} |
||||
|
|
||||
|
static char *to_string(const json_value *value) { |
||||
|
if (value->type == json_string) { |
||||
|
return strndup(value->u.string.ptr, value->u.string.length); |
||||
|
} else if (value->type == json_integer) { |
||||
|
return strdup(itoa(value->u.integer)); |
||||
|
} else if (value->type == json_null) { |
||||
|
return "null"; |
||||
|
} else { |
||||
|
LOGE("%d\n", value->type); |
||||
|
FATAL("Invalid config format.\n"); |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static int to_int(const json_value *value) { |
||||
|
if (value->type == json_string) { |
||||
|
return atoi(value->u.string.ptr); |
||||
|
} else if (value->type == json_integer) { |
||||
|
return value->u.integer; |
||||
|
} else { |
||||
|
FATAL("Invalid config format.\n"); |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
jconf_t *read_jconf(const char* file) { |
||||
|
|
||||
|
static jconf_t conf; |
||||
|
|
||||
|
char *buf; |
||||
|
json_value *obj; |
||||
|
|
||||
|
FILE *f = fopen(file, "r"); |
||||
|
if (f == NULL) FATAL("Invalid config path.\n"); |
||||
|
|
||||
|
fseek(f, 0, SEEK_END); |
||||
|
long pos = ftell(f); |
||||
|
fseek(f, 0, SEEK_SET); |
||||
|
|
||||
|
if (pos >= MAX_CONF_SIZE) FATAL("Too large config file.\n"); |
||||
|
|
||||
|
buf = malloc(pos); |
||||
|
if (buf == NULL) FATAL("No enough memory.\n"); |
||||
|
|
||||
|
fread(buf, pos, 1, f); |
||||
|
fclose(f); |
||||
|
|
||||
|
obj = json_parse(buf); |
||||
|
if (obj->type == json_object) { |
||||
|
int i, j; |
||||
|
for (i = 0; i < obj->u.object.length; i++) { |
||||
|
char *name = obj->u.object.values[i].name; |
||||
|
json_value *value = obj->u.object.values[i].value; |
||||
|
if (strcmp(name, "server") == 0) { |
||||
|
if (value->type == json_array) { |
||||
|
for (j = 0; j < value->u.array.length; j++) { |
||||
|
if (j >= MAX_REMOTE_NUM) break; |
||||
|
json_value *v = value->u.array.values[j]; |
||||
|
conf.remote_host[j] = to_string(v); |
||||
|
conf.remote_num = j + 1; |
||||
|
} |
||||
|
} else if (value->type == json_string) { |
||||
|
conf.remote_host[0] = to_string(value); |
||||
|
conf.remote_num = 1; |
||||
|
} |
||||
|
} else if (strcmp(name, "server_port") == 0) { |
||||
|
conf.remote_port = to_string(value); |
||||
|
} else if (strcmp(name, "local_port") == 0) { |
||||
|
conf.local_port = to_string(value); |
||||
|
} else if (strcmp(name, "password") == 0) { |
||||
|
conf.password = to_string(value); |
||||
|
} else if (strcmp(name, "method") == 0) { |
||||
|
conf.method = to_string(value); |
||||
|
} else if (strcmp(name, "timeout") == 0) { |
||||
|
conf.timeout = to_string(value); |
||||
|
} |
||||
|
} |
||||
|
} else { |
||||
|
FATAL("Invalid config file\n"); |
||||
|
} |
||||
|
|
||||
|
free(buf); |
||||
|
json_value_free(obj); |
||||
|
return &conf; |
||||
|
|
||||
|
} |
@ -0,0 +1,19 @@ |
|||||
|
#ifndef _JCONF_H |
||||
|
#define _JCONF_H |
||||
|
|
||||
|
#define MAX_REMOTE_NUM 10 |
||||
|
#define MAX_CONF_SIZE 512 * 1024 |
||||
|
|
||||
|
typedef struct { |
||||
|
int remote_num; |
||||
|
char *remote_host[MAX_REMOTE_NUM]; |
||||
|
char *remote_port; |
||||
|
char *local_port; |
||||
|
char *password; |
||||
|
char *method; |
||||
|
char *timeout; |
||||
|
} jconf_t; |
||||
|
|
||||
|
jconf_t *read_jconf(const char* file); |
||||
|
|
||||
|
#endif // _JCONF_H |
@ -0,0 +1,838 @@ |
|||||
|
|
||||
|
/* vim: set et ts=3 sw=3 ft=c: |
||||
|
* |
||||
|
* Copyright (C) 2012 James McLaughlin et al. All rights reserved. |
||||
|
* https://github.com/udp/json-parser |
||||
|
* |
||||
|
* Redistribution and use in source and binary forms, with or without |
||||
|
* modification, are permitted provided that the following conditions |
||||
|
* are met: |
||||
|
* |
||||
|
* 1. Redistributions of source code must retain the above copyright |
||||
|
* notice, this list of conditions and the following disclaimer. |
||||
|
* |
||||
|
* 2. Redistributions in binary form must reproduce the above copyright |
||||
|
* notice, this list of conditions and the following disclaimer in the |
||||
|
* documentation and/or other materials provided with the distribution. |
||||
|
* |
||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||
|
* SUCH DAMAGE. |
||||
|
*/ |
||||
|
|
||||
|
#include "json.h" |
||||
|
|
||||
|
#ifdef _MSC_VER |
||||
|
#ifndef _CRT_SECURE_NO_WARNINGS |
||||
|
#define _CRT_SECURE_NO_WARNINGS |
||||
|
#endif |
||||
|
#endif |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
const struct _json_value json_value_none; /* zero-d by ctor */ |
||||
|
#else |
||||
|
const struct _json_value json_value_none = { 0 }; |
||||
|
#endif |
||||
|
|
||||
|
#include <stdlib.h> |
||||
|
#include <stdio.h> |
||||
|
#include <string.h> |
||||
|
#include <ctype.h> |
||||
|
#include <math.h> |
||||
|
|
||||
|
typedef unsigned short json_uchar; |
||||
|
|
||||
|
static unsigned char hex_value (json_char c) |
||||
|
{ |
||||
|
if (c >= 'A' && c <= 'F') |
||||
|
return (c - 'A') + 10; |
||||
|
|
||||
|
if (c >= 'a' && c <= 'f') |
||||
|
return (c - 'a') + 10; |
||||
|
|
||||
|
if (c >= '0' && c <= '9') |
||||
|
return c - '0'; |
||||
|
|
||||
|
return 0xFF; |
||||
|
} |
||||
|
|
||||
|
typedef struct |
||||
|
{ |
||||
|
json_settings settings; |
||||
|
int first_pass; |
||||
|
|
||||
|
unsigned long used_memory; |
||||
|
|
||||
|
unsigned int uint_max; |
||||
|
unsigned long ulong_max; |
||||
|
|
||||
|
} json_state; |
||||
|
|
||||
|
static void * json_alloc (json_state * state, unsigned long size, int zero) |
||||
|
{ |
||||
|
void * mem; |
||||
|
|
||||
|
if ((state->ulong_max - state->used_memory) < size) |
||||
|
return 0; |
||||
|
|
||||
|
if (state->settings.max_memory |
||||
|
&& (state->used_memory += size) > state->settings.max_memory) |
||||
|
{ |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
if (! (mem = zero ? calloc (size, 1) : malloc (size))) |
||||
|
return 0; |
||||
|
|
||||
|
return mem; |
||||
|
} |
||||
|
|
||||
|
static int new_value |
||||
|
(json_state * state, json_value ** top, json_value ** root, json_value ** alloc, json_type type) |
||||
|
{ |
||||
|
json_value * value; |
||||
|
int values_size; |
||||
|
|
||||
|
if (!state->first_pass) |
||||
|
{ |
||||
|
value = *top = *alloc; |
||||
|
*alloc = (*alloc)->_reserved.next_alloc; |
||||
|
|
||||
|
if (!*root) |
||||
|
*root = value; |
||||
|
|
||||
|
switch (value->type) |
||||
|
{ |
||||
|
case json_array: |
||||
|
|
||||
|
if (! (value->u.array.values = (json_value **) json_alloc |
||||
|
(state, value->u.array.length * sizeof (json_value *), 0)) ) |
||||
|
{ |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
value->u.array.length = 0; |
||||
|
break; |
||||
|
|
||||
|
case json_object: |
||||
|
|
||||
|
values_size = sizeof (*value->u.object.values) * value->u.object.length; |
||||
|
|
||||
|
if (! ((*(void **) &value->u.object.values) = json_alloc |
||||
|
(state, values_size + ((unsigned long) value->u.object.values), 0)) ) |
||||
|
{ |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
value->_reserved.object_mem = (*(char **) &value->u.object.values) + values_size; |
||||
|
|
||||
|
value->u.object.length = 0; |
||||
|
break; |
||||
|
|
||||
|
case json_string: |
||||
|
|
||||
|
if (! (value->u.string.ptr = (json_char *) json_alloc |
||||
|
(state, (value->u.string.length + 1) * sizeof (json_char), 0)) ) |
||||
|
{ |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
value->u.string.length = 0; |
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
break; |
||||
|
}; |
||||
|
|
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
value = (json_value *) json_alloc (state, sizeof (json_value), 1); |
||||
|
|
||||
|
if (!value) |
||||
|
return 0; |
||||
|
|
||||
|
if (!*root) |
||||
|
*root = value; |
||||
|
|
||||
|
value->type = type; |
||||
|
value->parent = *top; |
||||
|
|
||||
|
if (*alloc) |
||||
|
(*alloc)->_reserved.next_alloc = value; |
||||
|
|
||||
|
*alloc = *top = value; |
||||
|
|
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
#define e_off \ |
||||
|
((int) (i - cur_line_begin)) |
||||
|
|
||||
|
#define whitespace \ |
||||
|
case '\n': ++ cur_line; cur_line_begin = i; \ |
||||
|
case ' ': case '\t': case '\r' |
||||
|
|
||||
|
#define string_add(b) \ |
||||
|
do { if (!state.first_pass) string [string_length] = b; ++ string_length; } while (0); |
||||
|
|
||||
|
const static long |
||||
|
flag_next = 1, flag_reproc = 2, flag_need_comma = 4, flag_seek_value = 8, |
||||
|
flag_escaped = 16, flag_string = 32, flag_need_colon = 64, flag_done = 128, |
||||
|
flag_num_negative = 256, flag_num_zero = 512, flag_num_e = 1024, |
||||
|
flag_num_e_got_sign = 2048, flag_num_e_negative = 4096; |
||||
|
|
||||
|
json_value * json_parse_ex (json_settings * settings, const json_char * json, char * error_buf) |
||||
|
{ |
||||
|
json_char error [128]; |
||||
|
unsigned int cur_line; |
||||
|
const json_char * cur_line_begin, * i; |
||||
|
json_value * top, * root, * alloc = 0; |
||||
|
json_state state; |
||||
|
long flags; |
||||
|
long num_digits, num_fraction, num_e; |
||||
|
|
||||
|
error[0] = '\0'; |
||||
|
|
||||
|
memset (&state, 0, sizeof (json_state)); |
||||
|
memcpy (&state.settings, settings, sizeof (json_settings)); |
||||
|
|
||||
|
memset (&state.uint_max, 0xFF, sizeof (state.uint_max)); |
||||
|
memset (&state.ulong_max, 0xFF, sizeof (state.ulong_max)); |
||||
|
|
||||
|
state.uint_max -= 8; /* limit of how much can be added before next check */ |
||||
|
state.ulong_max -= 8; |
||||
|
|
||||
|
for (state.first_pass = 1; state.first_pass >= 0; -- state.first_pass) |
||||
|
{ |
||||
|
json_uchar uchar; |
||||
|
unsigned char uc_b1, uc_b2, uc_b3, uc_b4; |
||||
|
json_char * string; |
||||
|
unsigned int string_length; |
||||
|
|
||||
|
top = root = 0; |
||||
|
flags = flag_seek_value; |
||||
|
|
||||
|
cur_line = 1; |
||||
|
cur_line_begin = json; |
||||
|
|
||||
|
for (i = json ;; ++ i) |
||||
|
{ |
||||
|
json_char b = *i; |
||||
|
|
||||
|
if (flags & flag_done) |
||||
|
{ |
||||
|
if (!b) |
||||
|
break; |
||||
|
|
||||
|
switch (b) |
||||
|
{ |
||||
|
whitespace: |
||||
|
continue; |
||||
|
|
||||
|
default: |
||||
|
sprintf (error, "%d:%d: Trailing garbage: `%c`", cur_line, e_off, b); |
||||
|
goto e_failed; |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
if (flags & flag_string) |
||||
|
{ |
||||
|
if (!b) |
||||
|
{ sprintf (error, "Unexpected EOF in string (at %d:%d)", cur_line, e_off); |
||||
|
goto e_failed; |
||||
|
} |
||||
|
|
||||
|
if (string_length > state.uint_max) |
||||
|
goto e_overflow; |
||||
|
|
||||
|
if (flags & flag_escaped) |
||||
|
{ |
||||
|
flags &= ~ flag_escaped; |
||||
|
|
||||
|
switch (b) |
||||
|
{ |
||||
|
case 'b': string_add ('\b'); break; |
||||
|
case 'f': string_add ('\f'); break; |
||||
|
case 'n': string_add ('\n'); break; |
||||
|
case 'r': string_add ('\r'); break; |
||||
|
case 't': string_add ('\t'); break; |
||||
|
case 'u': |
||||
|
|
||||
|
if ((uc_b1 = hex_value (*++ i)) == 0xFF || (uc_b2 = hex_value (*++ i)) == 0xFF |
||||
|
|| (uc_b3 = hex_value (*++ i)) == 0xFF || (uc_b4 = hex_value (*++ i)) == 0xFF) |
||||
|
{ |
||||
|
sprintf (error, "Invalid character value `%c` (at %d:%d)", b, cur_line, e_off); |
||||
|
goto e_failed; |
||||
|
} |
||||
|
|
||||
|
uc_b1 = uc_b1 * 16 + uc_b2; |
||||
|
uc_b2 = uc_b3 * 16 + uc_b4; |
||||
|
|
||||
|
uchar = ((json_char) uc_b1) * 256 + uc_b2; |
||||
|
|
||||
|
if (sizeof (json_char) >= sizeof (json_uchar) || (uc_b1 == 0 && uc_b2 <= 0x7F)) |
||||
|
{ |
||||
|
string_add ((json_char) uchar); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if (uchar <= 0x7FF) |
||||
|
{ |
||||
|
if (state.first_pass) |
||||
|
string_length += 2; |
||||
|
else |
||||
|
{ string [string_length ++] = 0xC0 | ((uc_b2 & 0xC0) >> 6) | ((uc_b1 & 0x7) << 2); |
||||
|
string [string_length ++] = 0x80 | (uc_b2 & 0x3F); |
||||
|
} |
||||
|
|
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if (state.first_pass) |
||||
|
string_length += 3; |
||||
|
else |
||||
|
{ string [string_length ++] = 0xE0 | ((uc_b1 & 0xF0) >> 4); |
||||
|
string [string_length ++] = 0x80 | ((uc_b1 & 0xF) << 2) | ((uc_b2 & 0xC0) >> 6); |
||||
|
string [string_length ++] = 0x80 | (uc_b2 & 0x3F); |
||||
|
} |
||||
|
|
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
string_add (b); |
||||
|
}; |
||||
|
|
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if (b == '\\') |
||||
|
{ |
||||
|
flags |= flag_escaped; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if (b == '"') |
||||
|
{ |
||||
|
if (!state.first_pass) |
||||
|
string [string_length] = 0; |
||||
|
|
||||
|
flags &= ~ flag_string; |
||||
|
string = 0; |
||||
|
|
||||
|
switch (top->type) |
||||
|
{ |
||||
|
case json_string: |
||||
|
|
||||
|
top->u.string.length = string_length; |
||||
|
flags |= flag_next; |
||||
|
|
||||
|
break; |
||||
|
|
||||
|
case json_object: |
||||
|
|
||||
|
if (state.first_pass) |
||||
|
(*(json_char **) &top->u.object.values) += string_length + 1; |
||||
|
else |
||||
|
{ |
||||
|
top->u.object.values [top->u.object.length].name |
||||
|
= (json_char *) top->_reserved.object_mem; |
||||
|
|
||||
|
(*(json_char **) &top->_reserved.object_mem) += string_length + 1; |
||||
|
} |
||||
|
|
||||
|
flags |= flag_seek_value | flag_need_colon; |
||||
|
continue; |
||||
|
|
||||
|
default: |
||||
|
break; |
||||
|
}; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
string_add (b); |
||||
|
continue; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (flags & flag_seek_value) |
||||
|
{ |
||||
|
switch (b) |
||||
|
{ |
||||
|
whitespace: |
||||
|
continue; |
||||
|
|
||||
|
case ']': |
||||
|
|
||||
|
if (top->type == json_array) |
||||
|
flags = (flags & ~ (flag_need_comma | flag_seek_value)) | flag_next; |
||||
|
else if (!state.settings.settings & json_relaxed_commas) |
||||
|
{ sprintf (error, "%d:%d: Unexpected ]", cur_line, e_off); |
||||
|
goto e_failed; |
||||
|
} |
||||
|
|
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
|
||||
|
if (flags & flag_need_comma) |
||||
|
{ |
||||
|
if (b == ',') |
||||
|
{ flags &= ~ flag_need_comma; |
||||
|
continue; |
||||
|
} |
||||
|
else |
||||
|
{ sprintf (error, "%d:%d: Expected , before %c", cur_line, e_off, b); |
||||
|
goto e_failed; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (flags & flag_need_colon) |
||||
|
{ |
||||
|
if (b == ':') |
||||
|
{ flags &= ~ flag_need_colon; |
||||
|
continue; |
||||
|
} |
||||
|
else |
||||
|
{ sprintf (error, "%d:%d: Expected : before %c", cur_line, e_off, b); |
||||
|
goto e_failed; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
flags &= ~ flag_seek_value; |
||||
|
|
||||
|
switch (b) |
||||
|
{ |
||||
|
case '{': |
||||
|
|
||||
|
if (!new_value (&state, &top, &root, &alloc, json_object)) |
||||
|
goto e_alloc_failure; |
||||
|
|
||||
|
continue; |
||||
|
|
||||
|
case '[': |
||||
|
|
||||
|
if (!new_value (&state, &top, &root, &alloc, json_array)) |
||||
|
goto e_alloc_failure; |
||||
|
|
||||
|
flags |= flag_seek_value; |
||||
|
continue; |
||||
|
|
||||
|
case '"': |
||||
|
|
||||
|
if (!new_value (&state, &top, &root, &alloc, json_string)) |
||||
|
goto e_alloc_failure; |
||||
|
|
||||
|
flags |= flag_string; |
||||
|
|
||||
|
string = top->u.string.ptr; |
||||
|
string_length = 0; |
||||
|
|
||||
|
continue; |
||||
|
|
||||
|
case 't': |
||||
|
|
||||
|
if (*(++ i) != 'r' || *(++ i) != 'u' || *(++ i) != 'e') |
||||
|
goto e_unknown_value; |
||||
|
|
||||
|
if (!new_value (&state, &top, &root, &alloc, json_boolean)) |
||||
|
goto e_alloc_failure; |
||||
|
|
||||
|
top->u.boolean = 1; |
||||
|
|
||||
|
flags |= flag_next; |
||||
|
break; |
||||
|
|
||||
|
case 'f': |
||||
|
|
||||
|
if (*(++ i) != 'a' || *(++ i) != 'l' || *(++ i) != 's' || *(++ i) != 'e') |
||||
|
goto e_unknown_value; |
||||
|
|
||||
|
if (!new_value (&state, &top, &root, &alloc, json_boolean)) |
||||
|
goto e_alloc_failure; |
||||
|
|
||||
|
flags |= flag_next; |
||||
|
break; |
||||
|
|
||||
|
case 'n': |
||||
|
|
||||
|
if (*(++ i) != 'u' || *(++ i) != 'l' || *(++ i) != 'l') |
||||
|
goto e_unknown_value; |
||||
|
|
||||
|
if (!new_value (&state, &top, &root, &alloc, json_null)) |
||||
|
goto e_alloc_failure; |
||||
|
|
||||
|
flags |= flag_next; |
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
|
||||
|
if (isdigit (b) || b == '-') |
||||
|
{ |
||||
|
if (!new_value (&state, &top, &root, &alloc, json_integer)) |
||||
|
goto e_alloc_failure; |
||||
|
|
||||
|
if (!state.first_pass) |
||||
|
{ |
||||
|
while (isdigit (b) || b == '+' || b == '-' |
||||
|
|| b == 'e' || b == 'E' || b == '.') |
||||
|
{ |
||||
|
b = *++ i; |
||||
|
} |
||||
|
|
||||
|
flags |= flag_next | flag_reproc; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
flags &= ~ (flag_num_negative | flag_num_e | |
||||
|
flag_num_e_got_sign | flag_num_e_negative | |
||||
|
flag_num_zero); |
||||
|
|
||||
|
num_digits = 0; |
||||
|
num_fraction = 0; |
||||
|
num_e = 0; |
||||
|
|
||||
|
if (b != '-') |
||||
|
{ |
||||
|
flags |= flag_reproc; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
flags |= flag_num_negative; |
||||
|
continue; |
||||
|
} |
||||
|
else |
||||
|
{ sprintf (error, "%d:%d: Unexpected %c when seeking value", cur_line, e_off, b); |
||||
|
goto e_failed; |
||||
|
} |
||||
|
}; |
||||
|
}; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
switch (top->type) |
||||
|
{ |
||||
|
case json_object: |
||||
|
|
||||
|
switch (b) |
||||
|
{ |
||||
|
whitespace: |
||||
|
continue; |
||||
|
|
||||
|
case '"': |
||||
|
|
||||
|
if (flags & flag_need_comma && (!state.settings.settings & json_relaxed_commas)) |
||||
|
{ |
||||
|
sprintf (error, "%d:%d: Expected , before \"", cur_line, e_off); |
||||
|
goto e_failed; |
||||
|
} |
||||
|
|
||||
|
flags |= flag_string; |
||||
|
|
||||
|
string = (json_char *) top->_reserved.object_mem; |
||||
|
string_length = 0; |
||||
|
|
||||
|
break; |
||||
|
|
||||
|
case '}': |
||||
|
|
||||
|
flags = (flags & ~ flag_need_comma) | flag_next; |
||||
|
break; |
||||
|
|
||||
|
case ',': |
||||
|
|
||||
|
if (flags & flag_need_comma) |
||||
|
{ |
||||
|
flags &= ~ flag_need_comma; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
default: |
||||
|
|
||||
|
sprintf (error, "%d:%d: Unexpected `%c` in object", cur_line, e_off, b); |
||||
|
goto e_failed; |
||||
|
}; |
||||
|
|
||||
|
break; |
||||
|
|
||||
|
case json_integer: |
||||
|
case json_double: |
||||
|
|
||||
|
if (isdigit (b)) |
||||
|
{ |
||||
|
++ num_digits; |
||||
|
|
||||
|
if (top->type == json_integer || flags & flag_num_e) |
||||
|
{ |
||||
|
if (! (flags & flag_num_e)) |
||||
|
{ |
||||
|
if (flags & flag_num_zero) |
||||
|
{ sprintf (error, "%d:%d: Unexpected `0` before `%c`", cur_line, e_off, b); |
||||
|
goto e_failed; |
||||
|
} |
||||
|
|
||||
|
if (num_digits == 1 && b == '0') |
||||
|
flags |= flag_num_zero; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
flags |= flag_num_e_got_sign; |
||||
|
num_e = (num_e * 10) + (b - '0'); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
top->u.integer = (top->u.integer * 10) + (b - '0'); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
num_fraction = (num_fraction * 10) + (b - '0'); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if (b == '+' || b == '-') |
||||
|
{ |
||||
|
if ( (flags & flag_num_e) && !(flags & flag_num_e_got_sign)) |
||||
|
{ |
||||
|
flags |= flag_num_e_got_sign; |
||||
|
|
||||
|
if (b == '-') |
||||
|
flags |= flag_num_e_negative; |
||||
|
|
||||
|
continue; |
||||
|
} |
||||
|
} |
||||
|
else if (b == '.' && top->type == json_integer) |
||||
|
{ |
||||
|
if (!num_digits) |
||||
|
{ sprintf (error, "%d:%d: Expected digit before `.`", cur_line, e_off); |
||||
|
goto e_failed; |
||||
|
} |
||||
|
|
||||
|
top->type = json_double; |
||||
|
top->u.dbl = top->u.integer; |
||||
|
|
||||
|
num_digits = 0; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if (! (flags & flag_num_e)) |
||||
|
{ |
||||
|
if (top->type == json_double) |
||||
|
{ |
||||
|
if (!num_digits) |
||||
|
{ sprintf (error, "%d:%d: Expected digit after `.`", cur_line, e_off); |
||||
|
goto e_failed; |
||||
|
} |
||||
|
|
||||
|
top->u.dbl += ((double) num_fraction) / (pow (10, (double) num_digits)); |
||||
|
} |
||||
|
|
||||
|
if (b == 'e' || b == 'E') |
||||
|
{ |
||||
|
flags |= flag_num_e; |
||||
|
|
||||
|
if (top->type == json_integer) |
||||
|
{ |
||||
|
top->type = json_double; |
||||
|
top->u.dbl = top->u.integer; |
||||
|
} |
||||
|
|
||||
|
num_digits = 0; |
||||
|
flags &= ~ flag_num_zero; |
||||
|
|
||||
|
continue; |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (!num_digits) |
||||
|
{ sprintf (error, "%d:%d: Expected digit after `e`", cur_line, e_off); |
||||
|
goto e_failed; |
||||
|
} |
||||
|
|
||||
|
top->u.dbl *= pow (10, (double) (flags & flag_num_e_negative ? - num_e : num_e)); |
||||
|
} |
||||
|
|
||||
|
if (flags & flag_num_negative) |
||||
|
{ |
||||
|
if (top->type == json_integer) |
||||
|
top->u.integer = - top->u.integer; |
||||
|
else |
||||
|
top->u.dbl = - top->u.dbl; |
||||
|
} |
||||
|
|
||||
|
flags |= flag_next | flag_reproc; |
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
break; |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
if (flags & flag_reproc) |
||||
|
{ |
||||
|
flags &= ~ flag_reproc; |
||||
|
-- i; |
||||
|
} |
||||
|
|
||||
|
if (flags & flag_next) |
||||
|
{ |
||||
|
flags = (flags & ~ flag_next) | flag_need_comma; |
||||
|
|
||||
|
if (!top->parent) |
||||
|
{ |
||||
|
/* root value done */ |
||||
|
|
||||
|
flags |= flag_done; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if (top->parent->type == json_array) |
||||
|
flags |= flag_seek_value; |
||||
|
|
||||
|
if (!state.first_pass) |
||||
|
{ |
||||
|
json_value * parent = top->parent; |
||||
|
|
||||
|
switch (parent->type) |
||||
|
{ |
||||
|
case json_object: |
||||
|
|
||||
|
parent->u.object.values |
||||
|
[parent->u.object.length].value = top; |
||||
|
|
||||
|
break; |
||||
|
|
||||
|
case json_array: |
||||
|
|
||||
|
parent->u.array.values |
||||
|
[parent->u.array.length] = top; |
||||
|
|
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
break; |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
if ( (++ top->parent->u.array.length) > state.uint_max) |
||||
|
goto e_overflow; |
||||
|
|
||||
|
top = top->parent; |
||||
|
|
||||
|
continue; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
alloc = root; |
||||
|
} |
||||
|
|
||||
|
return root; |
||||
|
|
||||
|
e_unknown_value: |
||||
|
|
||||
|
sprintf (error, "%d:%d: Unknown value", cur_line, e_off); |
||||
|
goto e_failed; |
||||
|
|
||||
|
e_alloc_failure: |
||||
|
|
||||
|
strcpy (error, "Memory allocation failure"); |
||||
|
goto e_failed; |
||||
|
|
||||
|
e_overflow: |
||||
|
|
||||
|
sprintf (error, "%d:%d: Too long (caught overflow)", cur_line, e_off); |
||||
|
goto e_failed; |
||||
|
|
||||
|
e_failed: |
||||
|
|
||||
|
if (error_buf) |
||||
|
{ |
||||
|
if (*error) |
||||
|
strcpy (error_buf, error); |
||||
|
else |
||||
|
strcpy (error_buf, "Unknown error"); |
||||
|
} |
||||
|
|
||||
|
if (state.first_pass) |
||||
|
alloc = root; |
||||
|
|
||||
|
while (alloc) |
||||
|
{ |
||||
|
top = alloc->_reserved.next_alloc; |
||||
|
free (alloc); |
||||
|
alloc = top; |
||||
|
} |
||||
|
|
||||
|
if (!state.first_pass) |
||||
|
json_value_free (root); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
json_value * json_parse (const json_char * json) |
||||
|
{ |
||||
|
json_settings settings; |
||||
|
memset (&settings, 0, sizeof (json_settings)); |
||||
|
|
||||
|
return json_parse_ex (&settings, json, 0); |
||||
|
} |
||||
|
|
||||
|
void json_value_free (json_value * value) |
||||
|
{ |
||||
|
json_value * cur_value; |
||||
|
|
||||
|
if (!value) |
||||
|
return; |
||||
|
|
||||
|
value->parent = 0; |
||||
|
|
||||
|
while (value) |
||||
|
{ |
||||
|
switch (value->type) |
||||
|
{ |
||||
|
case json_array: |
||||
|
|
||||
|
if (!value->u.array.length) |
||||
|
{ |
||||
|
free (value->u.array.values); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
value = value->u.array.values [-- value->u.array.length]; |
||||
|
continue; |
||||
|
|
||||
|
case json_object: |
||||
|
|
||||
|
if (!value->u.object.length) |
||||
|
{ |
||||
|
free (value->u.object.values); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
value = value->u.object.values [-- value->u.object.length].value; |
||||
|
continue; |
||||
|
|
||||
|
case json_string: |
||||
|
|
||||
|
free (value->u.string.ptr); |
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
break; |
||||
|
}; |
||||
|
|
||||
|
cur_value = value; |
||||
|
value = value->parent; |
||||
|
free (cur_value); |
||||
|
} |
||||
|
} |
||||
|
|
@ -0,0 +1,222 @@ |
|||||
|
|
||||
|
/* vim: set et ts=3 sw=3 ft=c: |
||||
|
* |
||||
|
* Copyright (C) 2012 James McLaughlin et al. All rights reserved. |
||||
|
* https://github.com/udp/json-parser |
||||
|
* |
||||
|
* Redistribution and use in source and binary forms, with or without |
||||
|
* modification, are permitted provided that the following conditions |
||||
|
* are met: |
||||
|
* |
||||
|
* 1. Redistributions of source code must retain the above copyright |
||||
|
* notice, this list of conditions and the following disclaimer. |
||||
|
* |
||||
|
* 2. Redistributions in binary form must reproduce the above copyright |
||||
|
* notice, this list of conditions and the following disclaimer in the |
||||
|
* documentation and/or other materials provided with the distribution. |
||||
|
* |
||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||
|
* SUCH DAMAGE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef _JSON_H |
||||
|
#define _JSON_H |
||||
|
|
||||
|
#ifndef json_char |
||||
|
#define json_char char |
||||
|
#endif |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
|
||||
|
#include <string.h> |
||||
|
|
||||
|
extern "C" |
||||
|
{ |
||||
|
|
||||
|
#endif |
||||
|
|
||||
|
typedef struct |
||||
|
{ |
||||
|
unsigned long max_memory; |
||||
|
int settings; |
||||
|
|
||||
|
} json_settings; |
||||
|
|
||||
|
#define json_relaxed_commas 1 |
||||
|
|
||||
|
typedef enum |
||||
|
{ |
||||
|
json_none, |
||||
|
json_object, |
||||
|
json_array, |
||||
|
json_integer, |
||||
|
json_double, |
||||
|
json_string, |
||||
|
json_boolean, |
||||
|
json_null |
||||
|
|
||||
|
} json_type; |
||||
|
|
||||
|
extern const struct _json_value json_value_none; |
||||
|
|
||||
|
typedef struct _json_value |
||||
|
{ |
||||
|
struct _json_value * parent; |
||||
|
|
||||
|
json_type type; |
||||
|
|
||||
|
union |
||||
|
{ |
||||
|
int boolean; |
||||
|
long integer; |
||||
|
double dbl; |
||||
|
|
||||
|
struct |
||||
|
{ |
||||
|
unsigned int length; |
||||
|
json_char * ptr; /* null terminated */ |
||||
|
|
||||
|
} string; |
||||
|
|
||||
|
struct |
||||
|
{ |
||||
|
unsigned int length; |
||||
|
|
||||
|
struct |
||||
|
{ |
||||
|
json_char * name; |
||||
|
struct _json_value * value; |
||||
|
|
||||
|
} * values; |
||||
|
|
||||
|
} object; |
||||
|
|
||||
|
struct |
||||
|
{ |
||||
|
unsigned int length; |
||||
|
struct _json_value ** values; |
||||
|
|
||||
|
} array; |
||||
|
|
||||
|
} u; |
||||
|
|
||||
|
union |
||||
|
{ |
||||
|
struct _json_value * next_alloc; |
||||
|
void * object_mem; |
||||
|
|
||||
|
} _reserved; |
||||
|
|
||||
|
|
||||
|
/* Some C++ operator sugar */ |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
|
||||
|
public: |
||||
|
|
||||
|
inline _json_value () |
||||
|
{ memset (this, 0, sizeof (_json_value)); |
||||
|
} |
||||
|
|
||||
|
inline const struct _json_value &operator [] (int index) const |
||||
|
{ |
||||
|
if (type != json_array || index < 0 |
||||
|
|| ((unsigned int) index) >= u.array.length) |
||||
|
{ |
||||
|
return json_value_none; |
||||
|
} |
||||
|
|
||||
|
return *u.array.values [index]; |
||||
|
} |
||||
|
|
||||
|
inline const struct _json_value &operator [] (const char * index) const |
||||
|
{ |
||||
|
if (type != json_object) |
||||
|
return json_value_none; |
||||
|
|
||||
|
for (unsigned int i = 0; i < u.object.length; ++ i) |
||||
|
if (!strcmp (u.object.values [i].name, index)) |
||||
|
return *u.object.values [i].value; |
||||
|
|
||||
|
return json_value_none; |
||||
|
} |
||||
|
|
||||
|
inline operator const char * () const |
||||
|
{ |
||||
|
switch (type) |
||||
|
{ |
||||
|
case json_string: |
||||
|
return u.string.ptr; |
||||
|
|
||||
|
default: |
||||
|
return ""; |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
inline operator long () const |
||||
|
{ |
||||
|
switch (type) |
||||
|
{ |
||||
|
case json_integer: |
||||
|
return u.integer; |
||||
|
|
||||
|
case json_double: |
||||
|
return (long) u.dbl; |
||||
|
|
||||
|
default: |
||||
|
return 0; |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
inline operator bool () const |
||||
|
{ |
||||
|
if (type != json_boolean) |
||||
|
return false; |
||||
|
|
||||
|
return u.boolean != 0; |
||||
|
} |
||||
|
|
||||
|
inline operator double () const |
||||
|
{ |
||||
|
switch (type) |
||||
|
{ |
||||
|
case json_integer: |
||||
|
return u.integer; |
||||
|
|
||||
|
case json_double: |
||||
|
return u.dbl; |
||||
|
|
||||
|
default: |
||||
|
return 0; |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
#endif |
||||
|
|
||||
|
} json_value; |
||||
|
|
||||
|
json_value * json_parse |
||||
|
(const json_char * json); |
||||
|
|
||||
|
json_value * json_parse_ex |
||||
|
(json_settings * settings, const json_char * json, char * error); |
||||
|
|
||||
|
void json_value_free (json_value *); |
||||
|
|
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} /* extern "C" */ |
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
|
|
||||
|
|
@ -0,0 +1,67 @@ |
|||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <unistd.h> |
||||
|
|
||||
|
#include "utils.h" |
||||
|
|
||||
|
void FATAL(const char *msg) { |
||||
|
fprintf(stderr, "%s", msg); |
||||
|
exit(-1); |
||||
|
} |
||||
|
|
||||
|
void usage() { |
||||
|
printf("usage: ss -s server_host -p server_port -l local_port\n"); |
||||
|
printf(" -k password [-m encrypt_method] [-f pid_file]\n"); |
||||
|
printf("\n"); |
||||
|
printf("options:\n"); |
||||
|
printf(" encrypt_method: table, rc4\n"); |
||||
|
printf(" pid_file: valid path to the pid file\n"); |
||||
|
} |
||||
|
|
||||
|
void demonize(const char* path) { |
||||
|
|
||||
|
/* Our process ID and Session ID */ |
||||
|
pid_t pid, sid; |
||||
|
|
||||
|
/* Fork off the parent process */ |
||||
|
pid = fork(); |
||||
|
if (pid < 0) { |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
|
||||
|
/* If we got a good PID, then |
||||
|
we can exit the parent process. */ |
||||
|
if (pid > 0) { |
||||
|
FILE *file = fopen(path, "w"); |
||||
|
if (file == NULL) FATAL("Invalid pid file\n"); |
||||
|
|
||||
|
fprintf(file, "%d", pid); |
||||
|
fclose(file); |
||||
|
exit(EXIT_SUCCESS); |
||||
|
} |
||||
|
|
||||
|
/* Change the file mode mask */ |
||||
|
umask(0); |
||||
|
|
||||
|
/* Open any logs here */ |
||||
|
|
||||
|
/* Create a new SID for the child process */ |
||||
|
sid = setsid(); |
||||
|
if (sid < 0) { |
||||
|
/* Log the failure */ |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
|
||||
|
/* Change the current working directory */ |
||||
|
if ((chdir("/")) < 0) { |
||||
|
/* Log the failure */ |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
|
||||
|
/* Close out the standard file descriptors */ |
||||
|
close(STDIN_FILENO); |
||||
|
close(STDOUT_FILENO); |
||||
|
close(STDERR_FILENO); |
||||
|
|
||||
|
} |
||||
|
|
@ -0,0 +1,11 @@ |
|||||
|
#ifndef _UTILS_H |
||||
|
#define _UTILS_H |
||||
|
|
||||
|
#define LOGD(...) ((void)fprintf(stdout, __VA_ARGS__)) |
||||
|
#define LOGE(...) ((void)fprintf(stderr, __VA_ARGS__)) |
||||
|
|
||||
|
void FATAL(const char *msg); |
||||
|
void usage(void); |
||||
|
void demonize(const char* path); |
||||
|
|
||||
|
#endif // _UTILS_H |
Write
Preview
Loading…
Cancel
Save