Merge libubox with the version 2016.02.26 from its git.
This commit is contained in:
1
3P/libubox/.gitignore
vendored
1
3P/libubox/.gitignore
vendored
@@ -8,3 +8,4 @@ CMakeFiles
|
||||
install_manifest.txt
|
||||
jshn
|
||||
*-example
|
||||
tests.*
|
||||
|
||||
71
3P/libubox/CMakeLists.txt
Normal file
71
3P/libubox/CMakeLists.txt
Normal file
@@ -0,0 +1,71 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
INCLUDE(CheckLibraryExists)
|
||||
INCLUDE(CheckFunctionExists)
|
||||
|
||||
PROJECT(ubox C)
|
||||
ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -g3 -Wmissing-declarations)
|
||||
|
||||
OPTION(BUILD_LUA "build Lua plugin" ON)
|
||||
OPTION(BUILD_EXAMPLES "build examples" ON)
|
||||
|
||||
INCLUDE(FindPkgConfig)
|
||||
PKG_SEARCH_MODULE(JSONC json-c)
|
||||
IF(JSONC_FOUND)
|
||||
ADD_DEFINITIONS(-DJSONC)
|
||||
INCLUDE_DIRECTORIES(${JSONC_INCLUDE_DIRS})
|
||||
ENDIF()
|
||||
|
||||
SET(SOURCES avl.c avl-cmp.c blob.c blobmsg.c uloop.c usock.c ustream.c ustream-fd.c vlist.c utils.c safe_list.c runqueue.c md5.c kvlist.c ulog.c base64.c)
|
||||
|
||||
ADD_LIBRARY(ubox SHARED ${SOURCES})
|
||||
ADD_LIBRARY(ubox-static STATIC ${SOURCES})
|
||||
SET_TARGET_PROPERTIES(ubox-static PROPERTIES OUTPUT_NAME ubox)
|
||||
|
||||
SET(LIBS)
|
||||
CHECK_FUNCTION_EXISTS(clock_gettime HAVE_GETTIME)
|
||||
IF(NOT HAVE_GETTIME)
|
||||
CHECK_LIBRARY_EXISTS(rt clock_gettime "" NEED_GETTIME)
|
||||
IF(NEED_GETTIME)
|
||||
TARGET_LINK_LIBRARIES(ubox rt)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
FILE(GLOB headers *.h)
|
||||
INSTALL(FILES ${headers}
|
||||
DESTINATION include/libubox
|
||||
)
|
||||
INSTALL(TARGETS ubox ubox-static
|
||||
ARCHIVE DESTINATION lib
|
||||
LIBRARY DESTINATION lib
|
||||
)
|
||||
|
||||
ADD_SUBDIRECTORY(lua)
|
||||
ADD_SUBDIRECTORY(examples)
|
||||
|
||||
find_library(json NAMES json-c)
|
||||
IF(EXISTS ${json})
|
||||
ADD_LIBRARY(blobmsg_json SHARED blobmsg_json.c)
|
||||
TARGET_LINK_LIBRARIES(blobmsg_json ubox ${json})
|
||||
|
||||
ADD_LIBRARY(blobmsg_json-static STATIC blobmsg_json.c)
|
||||
SET_TARGET_PROPERTIES(blobmsg_json-static
|
||||
PROPERTIES OUTPUT_NAME blobmsg_json)
|
||||
|
||||
ADD_EXECUTABLE(jshn jshn.c)
|
||||
TARGET_LINK_LIBRARIES(jshn blobmsg_json ${json})
|
||||
|
||||
ADD_LIBRARY(json_script SHARED json_script.c)
|
||||
TARGET_LINK_LIBRARIES(json_script ubox)
|
||||
|
||||
INSTALL(TARGETS blobmsg_json blobmsg_json-static jshn json_script
|
||||
ARCHIVE DESTINATION lib
|
||||
LIBRARY DESTINATION lib
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
|
||||
FILE(GLOB scripts sh/*.sh)
|
||||
INSTALL(FILES ${scripts}
|
||||
DESTINATION share/libubox
|
||||
)
|
||||
|
||||
ENDIF()
|
||||
327
3P/libubox/base64.c
Normal file
327
3P/libubox/base64.c
Normal file
@@ -0,0 +1,327 @@
|
||||
/*
|
||||
* base64 - libubox base64 functions
|
||||
*
|
||||
* Copyright (C) 2015 Felix Fietkau <nbd@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $OpenBSD: base64.c,v 1.7 2013/12/31 02:32:56 tedu Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1996 by Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
||||
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
||||
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright (c) 1995 by International Business Machines, Inc.
|
||||
*
|
||||
* International Business Machines, Inc. (hereinafter called IBM) grants
|
||||
* permission under its copyrights to use, copy, modify, and distribute this
|
||||
* Software with or without fee, provided that the above copyright notice and
|
||||
* all paragraphs of this notice appear in all copies, and that the name of IBM
|
||||
* not be used in connection with the marketing of any product incorporating
|
||||
* the Software or modifications thereof, without specific, written prior
|
||||
* permission.
|
||||
*
|
||||
* To the extent it has a right to do so, IBM grants an immunity from suit
|
||||
* under its patents, if any, for the use, sale or manufacture of products to
|
||||
* the extent that such products are used for performing Domain Name System
|
||||
* dynamic updates in TCP/IP networks by means of the Software. No immunity is
|
||||
* granted for any product per se or for any other function of any product.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
|
||||
* DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
|
||||
* IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "utils.h"
|
||||
|
||||
static const char Base64[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static const char Pad64 = '=';
|
||||
|
||||
/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
|
||||
The following encoding technique is taken from RFC 1521 by Borenstein
|
||||
and Freed. It is reproduced here in a slightly edited form for
|
||||
convenience.
|
||||
|
||||
A 65-character subset of US-ASCII is used, enabling 6 bits to be
|
||||
represented per printable character. (The extra 65th character, "=",
|
||||
is used to signify a special processing function.)
|
||||
|
||||
The encoding process represents 24-bit groups of input bits as output
|
||||
strings of 4 encoded characters. Proceeding from left to right, a
|
||||
24-bit input group is formed by concatenating 3 8-bit input groups.
|
||||
These 24 bits are then treated as 4 concatenated 6-bit groups, each
|
||||
of which is translated into a single digit in the base64 alphabet.
|
||||
|
||||
Each 6-bit group is used as an index into an array of 64 printable
|
||||
characters. The character referenced by the index is placed in the
|
||||
output string.
|
||||
|
||||
Table 1: The Base64 Alphabet
|
||||
|
||||
Value Encoding Value Encoding Value Encoding Value Encoding
|
||||
0 A 17 R 34 i 51 z
|
||||
1 B 18 S 35 j 52 0
|
||||
2 C 19 T 36 k 53 1
|
||||
3 D 20 U 37 l 54 2
|
||||
4 E 21 V 38 m 55 3
|
||||
5 F 22 W 39 n 56 4
|
||||
6 G 23 X 40 o 57 5
|
||||
7 H 24 Y 41 p 58 6
|
||||
8 I 25 Z 42 q 59 7
|
||||
9 J 26 a 43 r 60 8
|
||||
10 K 27 b 44 s 61 9
|
||||
11 L 28 c 45 t 62 +
|
||||
12 M 29 d 46 u 63 /
|
||||
13 N 30 e 47 v
|
||||
14 O 31 f 48 w (pad) =
|
||||
15 P 32 g 49 x
|
||||
16 Q 33 h 50 y
|
||||
|
||||
Special processing is performed if fewer than 24 bits are available
|
||||
at the end of the data being encoded. A full encoding quantum is
|
||||
always completed at the end of a quantity. When fewer than 24 input
|
||||
bits are available in an input group, zero bits are added (on the
|
||||
right) to form an integral number of 6-bit groups. Padding at the
|
||||
end of the data is performed using the '=' character.
|
||||
|
||||
Since all base64 input is an integral number of octets, only the
|
||||
-------------------------------------------------
|
||||
following cases can arise:
|
||||
|
||||
(1) the final quantum of encoding input is an integral
|
||||
multiple of 24 bits; here, the final unit of encoded
|
||||
output will be an integral multiple of 4 characters
|
||||
with no "=" padding,
|
||||
(2) the final quantum of encoding input is exactly 8 bits;
|
||||
here, the final unit of encoded output will be two
|
||||
characters followed by two "=" padding characters, or
|
||||
(3) the final quantum of encoding input is exactly 16 bits;
|
||||
here, the final unit of encoded output will be three
|
||||
characters followed by one "=" padding character.
|
||||
*/
|
||||
|
||||
int b64_encode(const void *_src, size_t srclength,
|
||||
void *dest, size_t targsize)
|
||||
{
|
||||
const unsigned char *src = _src;
|
||||
char *target = dest;
|
||||
size_t datalength = 0;
|
||||
u_char input[3] = {0};
|
||||
u_char output[4];
|
||||
int i;
|
||||
|
||||
while (2 < srclength) {
|
||||
input[0] = *src++;
|
||||
input[1] = *src++;
|
||||
input[2] = *src++;
|
||||
srclength -= 3;
|
||||
|
||||
output[0] = input[0] >> 2;
|
||||
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
|
||||
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
|
||||
output[3] = input[2] & 0x3f;
|
||||
|
||||
if (datalength + 4 > targsize)
|
||||
return (-1);
|
||||
target[datalength++] = Base64[output[0]];
|
||||
target[datalength++] = Base64[output[1]];
|
||||
target[datalength++] = Base64[output[2]];
|
||||
target[datalength++] = Base64[output[3]];
|
||||
}
|
||||
|
||||
/* Now we worry about padding. */
|
||||
if (0 != srclength) {
|
||||
/* Get what's left. */
|
||||
input[0] = input[1] = input[2] = '\0';
|
||||
for (i = 0; i < srclength; i++)
|
||||
input[i] = *src++;
|
||||
|
||||
output[0] = input[0] >> 2;
|
||||
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
|
||||
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
|
||||
|
||||
if (datalength + 4 > targsize)
|
||||
return (-1);
|
||||
target[datalength++] = Base64[output[0]];
|
||||
target[datalength++] = Base64[output[1]];
|
||||
if (srclength == 1)
|
||||
target[datalength++] = Pad64;
|
||||
else
|
||||
target[datalength++] = Base64[output[2]];
|
||||
target[datalength++] = Pad64;
|
||||
}
|
||||
if (datalength >= targsize)
|
||||
return (-1);
|
||||
target[datalength] = '\0'; /* Returned value doesn't count \0. */
|
||||
return (datalength);
|
||||
}
|
||||
|
||||
/* skips all whitespace anywhere.
|
||||
converts characters, four at a time, starting at (or after)
|
||||
src from base - 64 numbers into three 8 bit bytes in the target area.
|
||||
it returns the number of data bytes stored at the target, or -1 on error.
|
||||
*/
|
||||
|
||||
int b64_decode(const void *_src, void *dest, size_t targsize)
|
||||
{
|
||||
const char *src = _src;
|
||||
unsigned char *target = dest;
|
||||
int tarindex, state, ch;
|
||||
u_char nextbyte;
|
||||
char *pos;
|
||||
|
||||
state = 0;
|
||||
tarindex = 0;
|
||||
|
||||
while ((ch = (unsigned char)*src++) != '\0') {
|
||||
if (isspace(ch)) /* Skip whitespace anywhere. */
|
||||
continue;
|
||||
|
||||
if (ch == Pad64)
|
||||
break;
|
||||
|
||||
pos = strchr(Base64, ch);
|
||||
if (pos == 0) /* A non-base64 character. */
|
||||
return (-1);
|
||||
|
||||
switch (state) {
|
||||
case 0:
|
||||
if (target) {
|
||||
if (tarindex >= targsize)
|
||||
return (-1);
|
||||
target[tarindex] = (pos - Base64) << 2;
|
||||
}
|
||||
state = 1;
|
||||
break;
|
||||
case 1:
|
||||
if (target) {
|
||||
if (tarindex >= targsize)
|
||||
return (-1);
|
||||
target[tarindex] |= (pos - Base64) >> 4;
|
||||
nextbyte = ((pos - Base64) & 0x0f) << 4;
|
||||
if (tarindex + 1 < targsize)
|
||||
target[tarindex+1] = nextbyte;
|
||||
else if (nextbyte)
|
||||
return (-1);
|
||||
}
|
||||
tarindex++;
|
||||
state = 2;
|
||||
break;
|
||||
case 2:
|
||||
if (target) {
|
||||
if (tarindex >= targsize)
|
||||
return (-1);
|
||||
target[tarindex] |= (pos - Base64) >> 2;
|
||||
nextbyte = ((pos - Base64) & 0x03) << 6;
|
||||
if (tarindex + 1 < targsize)
|
||||
target[tarindex+1] = nextbyte;
|
||||
else if (nextbyte)
|
||||
return (-1);
|
||||
}
|
||||
tarindex++;
|
||||
state = 3;
|
||||
break;
|
||||
case 3:
|
||||
if (target) {
|
||||
if (tarindex >= targsize)
|
||||
return (-1);
|
||||
target[tarindex] |= (pos - Base64);
|
||||
}
|
||||
tarindex++;
|
||||
state = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We are done decoding Base-64 chars. Let's see if we ended
|
||||
* on a byte boundary, and/or with erroneous trailing characters.
|
||||
*/
|
||||
|
||||
if (ch == Pad64) { /* We got a pad char. */
|
||||
ch = (unsigned char)*src++; /* Skip it, get next. */
|
||||
switch (state) {
|
||||
case 0: /* Invalid = in first position */
|
||||
case 1: /* Invalid = in second position */
|
||||
return (-1);
|
||||
|
||||
case 2: /* Valid, means one byte of info */
|
||||
/* Skip any number of spaces. */
|
||||
for (; ch != '\0'; ch = (unsigned char)*src++)
|
||||
if (!isspace(ch))
|
||||
break;
|
||||
/* Make sure there is another trailing = sign. */
|
||||
if (ch != Pad64)
|
||||
return (-1);
|
||||
ch = (unsigned char)*src++; /* Skip the = */
|
||||
/* Fall through to "single trailing =" case. */
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case 3: /* Valid, means two bytes of info */
|
||||
/*
|
||||
* We know this char is an =. Is there anything but
|
||||
* whitespace after it?
|
||||
*/
|
||||
for (; ch != '\0'; ch = (unsigned char)*src++)
|
||||
if (!isspace(ch))
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* Now make sure for cases 2 and 3 that the "extra"
|
||||
* bits that slopped past the last full byte were
|
||||
* zeros. If we don't check them, they become a
|
||||
* subliminal channel.
|
||||
*/
|
||||
if (target && tarindex < targsize &&
|
||||
target[tarindex] != 0)
|
||||
return (-1);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* We ended by seeing the end of the string. Make sure we
|
||||
* have no partial bytes lying around.
|
||||
*/
|
||||
if (state != 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Null-terminate if we have room left */
|
||||
if (tarindex < targsize)
|
||||
target[tarindex] = 0;
|
||||
|
||||
return (tarindex);
|
||||
}
|
||||
@@ -262,7 +262,6 @@ blobmsg_alloc_string_buffer(struct blob_buf *buf, const char *name, unsigned int
|
||||
if (!attr)
|
||||
return NULL;
|
||||
|
||||
data_dest = blobmsg_data(attr);
|
||||
blob_set_raw_len(buf->head, blob_pad_len(buf->head) - blob_pad_len(attr));
|
||||
blob_set_raw_len(attr, blob_raw_len(attr) - maxlen);
|
||||
|
||||
|
||||
@@ -17,6 +17,12 @@
|
||||
#include "blobmsg.h"
|
||||
#include "blobmsg_json.h"
|
||||
|
||||
#ifdef JSONC
|
||||
#include <json.h>
|
||||
#else
|
||||
#include <json/json.h>
|
||||
#endif
|
||||
|
||||
bool blobmsg_add_object(struct blob_buf *b, json_object *obj)
|
||||
{
|
||||
json_object_object_foreach(obj, key, val) {
|
||||
@@ -43,9 +49,6 @@ bool blobmsg_add_json_element(struct blob_buf *b, const char *name, json_object
|
||||
bool ret = true;
|
||||
void *c;
|
||||
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
switch (json_object_get_type(obj)) {
|
||||
case json_type_object:
|
||||
c = blobmsg_open_table(b, name);
|
||||
@@ -66,6 +69,9 @@ bool blobmsg_add_json_element(struct blob_buf *b, const char *name, json_object
|
||||
case json_type_int:
|
||||
blobmsg_add_u32(b, name, json_object_get_int(obj));
|
||||
break;
|
||||
case json_type_null:
|
||||
blobmsg_add_field(b, BLOBMSG_TYPE_UNSPEC, name, NULL, 0);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -76,7 +82,7 @@ static bool __blobmsg_add_json(struct blob_buf *b, json_object *obj)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (is_error(obj))
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
if (json_object_get_type(obj) != json_type_object)
|
||||
|
||||
@@ -16,17 +16,13 @@
|
||||
#ifndef __BLOBMSG_JSON_H
|
||||
#define __BLOBMSG_JSON_H
|
||||
|
||||
#ifdef JSONC
|
||||
#include <json.h>
|
||||
#else
|
||||
#include <json/json.h>
|
||||
#endif
|
||||
struct json_object;
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "blobmsg.h"
|
||||
|
||||
bool blobmsg_add_object(struct blob_buf *b, json_object *obj);
|
||||
bool blobmsg_add_json_element(struct blob_buf *b, const char *name, json_object *obj);
|
||||
bool blobmsg_add_object(struct blob_buf *b, struct json_object *obj);
|
||||
bool blobmsg_add_json_element(struct blob_buf *b, const char *name, struct json_object *obj);
|
||||
bool blobmsg_add_json_from_string(struct blob_buf *b, const char *str);
|
||||
bool blobmsg_add_json_from_file(struct blob_buf *b, const char *file);
|
||||
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
PROJECT(ubox-examples C)
|
||||
ADD_DEFINITIONS(-O1 -Wall -Werror --std=gnu99 -g3)
|
||||
IF (BUILD_EXAMPLES)
|
||||
PROJECT(ubox-examples C)
|
||||
ADD_DEFINITIONS(-O1 -Wall -Werror --std=gnu99 -g3)
|
||||
|
||||
IF(APPLE)
|
||||
INCLUDE_DIRECTORIES(/opt/local/include)
|
||||
LINK_DIRECTORIES(/opt/local/lib)
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/..)
|
||||
LINK_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/..)
|
||||
|
||||
FIND_LIBRARY(json NAMES json-c json)
|
||||
|
||||
ADD_EXECUTABLE(blobmsg-example blobmsg-example.c)
|
||||
TARGET_LINK_LIBRARIES(blobmsg-example ubox blobmsg_json ${json})
|
||||
|
||||
ADD_EXECUTABLE(ustream-example ustream-example.c)
|
||||
TARGET_LINK_LIBRARIES(ustream-example ubox)
|
||||
|
||||
ADD_EXECUTABLE(runqueue-example runqueue-example.c)
|
||||
TARGET_LINK_LIBRARIES(runqueue-example ubox)
|
||||
|
||||
ADD_EXECUTABLE(json_script-example json_script-example.c)
|
||||
TARGET_LINK_LIBRARIES(json_script-example ubox blobmsg_json json_script ${json})
|
||||
ENDIF()
|
||||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/..)
|
||||
LINK_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/..)
|
||||
|
||||
FIND_LIBRARY(json NAMES json-c json)
|
||||
|
||||
ADD_EXECUTABLE(blobmsg-example blobmsg-example.c)
|
||||
TARGET_LINK_LIBRARIES(blobmsg-example ubox blobmsg_json ${json})
|
||||
|
||||
ADD_EXECUTABLE(ustream-example ustream-example.c)
|
||||
TARGET_LINK_LIBRARIES(ustream-example ubox)
|
||||
|
||||
ADD_EXECUTABLE(runqueue-example runqueue-example.c)
|
||||
TARGET_LINK_LIBRARIES(runqueue-example ubox)
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "blobmsg.h"
|
||||
#include "blobmsg_json.h"
|
||||
|
||||
84
3P/libubox/examples/json_script-example.c
Normal file
84
3P/libubox/examples/json_script-example.c
Normal file
@@ -0,0 +1,84 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <json.h>
|
||||
#include "blobmsg.h"
|
||||
#include "blobmsg_json.h"
|
||||
#include "json_script.h"
|
||||
|
||||
struct json_script_ctx jctx;
|
||||
struct blob_buf b_vars;
|
||||
struct blob_buf b_script;
|
||||
|
||||
static void handle_command(struct json_script_ctx *ctx, const char *name,
|
||||
struct blob_attr *data, struct blob_attr *vars)
|
||||
{
|
||||
struct blob_attr *cur;
|
||||
int rem;
|
||||
|
||||
fprintf(stdout, "%s", name);
|
||||
blobmsg_for_each_attr(cur, data, rem)
|
||||
fprintf(stdout, " %s", (char *) blobmsg_data(cur));
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
static struct json_script_file *
|
||||
handle_file(struct json_script_ctx *ctx, const char *filename)
|
||||
{
|
||||
json_object *obj;
|
||||
|
||||
obj = json_object_from_file(filename);
|
||||
if (!obj) {
|
||||
fprintf(stderr, "load JSON data from %s failed.\n", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
blob_buf_init(&b_script, 0);
|
||||
blobmsg_add_json_element(&b_script, "", obj);
|
||||
json_object_put(obj);
|
||||
|
||||
return json_script_file_from_blobmsg(filename,
|
||||
blob_data(b_script.head), blob_len(b_script.head));
|
||||
}
|
||||
|
||||
static void usage(const char *prog, int exit_code)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [VARNAME=value] <filename_json_script>\n", prog);
|
||||
exit(exit_code);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
char *file = NULL;
|
||||
const char *prog = argv[0];
|
||||
|
||||
blobmsg_buf_init(&b_vars);
|
||||
blobmsg_buf_init(&b_script);
|
||||
|
||||
json_script_init(&jctx);
|
||||
jctx.handle_command = handle_command;
|
||||
jctx.handle_file = handle_file;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
char *sep = strchr(argv[i], '=');
|
||||
if (sep) {
|
||||
*sep = '\0';
|
||||
blobmsg_add_string(&b_vars, argv[i], sep + 1);
|
||||
} else if (!file) {
|
||||
file = argv[i];
|
||||
} else {
|
||||
usage(prog, -1);
|
||||
}
|
||||
}
|
||||
if (i < argc || !file)
|
||||
usage(prog, -2);
|
||||
|
||||
json_script_run(&jctx, file, b_vars.head);
|
||||
|
||||
json_script_free(&jctx);
|
||||
blob_buf_free(&b_script);
|
||||
blob_buf_free(&b_vars);
|
||||
|
||||
return 0;
|
||||
}
|
||||
38
3P/libubox/examples/json_script-example.json
Normal file
38
3P/libubox/examples/json_script-example.json
Normal file
@@ -0,0 +1,38 @@
|
||||
[
|
||||
[ "exec", "%EXECVAR%", "/%%/" ],
|
||||
[ "if",
|
||||
[ "eq", "EQVAR", "eqval" ],
|
||||
[ "exec_if", "%VAR%", "%%", "jk" ]
|
||||
],
|
||||
[ "case", "CASEVAR", {
|
||||
"caseval0": ["cmd_case_0", "cmd_case_arg0", "case_cmd_arg1"],
|
||||
"caseval1": ["cmd_case_1", "cmd_case_arg0", "case_cmd_arg1"]
|
||||
} ],
|
||||
|
||||
[ "if",
|
||||
[ "and", [ "eq", "EQVAR", "eqval" ],
|
||||
[ "has", "HASVAR" ],
|
||||
[ "regex", "REGEXVAR0", "regexval" ],
|
||||
[ "regex", "REGEXVAR1", [ "regexval10", "regexval11" ] ],
|
||||
[ "not", [ "eq", "NOTEQVAR", "noteqval" ] ] ],
|
||||
[ "exec_if_and", "%ANDVAR%" ]
|
||||
],
|
||||
|
||||
[ "if",
|
||||
[ "or", [ "eq", "EQVAR", "eqval" ],
|
||||
[ "has", "HASVAR" ],
|
||||
[ "regex", "REGEXVAR0", "regexval" ],
|
||||
[ "regex", "REGEXVAR1", [ "regexval10", "regexval11" ] ],
|
||||
[ "not", [ "eq", "NOTEQVAR", "noteqval" ] ] ],
|
||||
[ "exec_if_or", "%ORVAR%" ]
|
||||
],
|
||||
|
||||
[ "if",
|
||||
[ "isdir", "%ISDIRVAR%" ],
|
||||
[ "exec_isdir", "%ISDIRVAR%" ]
|
||||
],
|
||||
|
||||
[ "return", "foobar" ],
|
||||
|
||||
[ "exec_non_reachable", "Arghhh" ]
|
||||
]
|
||||
287
3P/libubox/examples/json_script-tests.sh
Normal file
287
3P/libubox/examples/json_script-tests.sh
Normal file
@@ -0,0 +1,287 @@
|
||||
JSON_SCRIPT=tests.json
|
||||
JSON_SCRIPT_BIN=./json_script-example
|
||||
FILE_STDOUT=tests.stdout
|
||||
FILE_STDERR=tests.stderr
|
||||
FILE_EXPECTED=tests.expected
|
||||
|
||||
call_json_script() {
|
||||
#export LD_PRELOAD=../libjson_script.so
|
||||
$JSON_SCRIPT_BIN "$@" "$JSON_SCRIPT" >"$FILE_STDOUT" 2>"$FILE_STDERR"
|
||||
}
|
||||
|
||||
assertStdioEquals() {
|
||||
local expected="$1"
|
||||
local file_stdio="$2"
|
||||
|
||||
echo "$expected" >"$FILE_EXPECTED"
|
||||
if [ -z "$expected" ]; then
|
||||
# we are expecting empty output, but we deliberately added a newline
|
||||
# with echo above, so adding another echo to compensate for that
|
||||
echo >>"$file_stdio"
|
||||
fi
|
||||
diff -up "$FILE_EXPECTED" "$file_stdio" >/dev/null 2>&1 || {
|
||||
cat >&2 <<EOF
|
||||
|--- expecting
|
||||
$expected<
|
||||
|--- actual
|
||||
$(cat $file_stdio)<
|
||||
|--- END
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
assertStdoutEquals() {
|
||||
assertStdioEquals "$1" "$FILE_STDOUT"
|
||||
}
|
||||
|
||||
assertStderrEquals() {
|
||||
assertStdioEquals "$1" "$FILE_STDERR"
|
||||
}
|
||||
|
||||
test_bad_json() {
|
||||
cat >"$JSON_SCRIPT" <<-EOF
|
||||
[
|
||||
[ ]
|
||||
[ ]
|
||||
]
|
||||
EOF
|
||||
call_json_script
|
||||
assertStderrEquals "load JSON data from $JSON_SCRIPT failed."
|
||||
}
|
||||
|
||||
test_expr_eq() {
|
||||
cat >"$JSON_SCRIPT" <<-EOF
|
||||
[
|
||||
[ "if",
|
||||
[ "eq", "VAR", "foo" ],
|
||||
[ "echo", "bar" ],
|
||||
[ "echo", "baz" ]
|
||||
]
|
||||
]
|
||||
EOF
|
||||
call_json_script "VAR=foo"
|
||||
assertStdoutEquals "echo bar"
|
||||
call_json_script "VAR=xxx"
|
||||
assertStdoutEquals "echo baz"
|
||||
}
|
||||
|
||||
test_expr_has() {
|
||||
cat >"$JSON_SCRIPT" <<-EOF
|
||||
[
|
||||
[ "if",
|
||||
[ "has", "VAR" ],
|
||||
[ "echo", "bar" ],
|
||||
[ "echo", "baz" ]
|
||||
]
|
||||
]
|
||||
EOF
|
||||
call_json_script "VAR=foo"
|
||||
assertStdoutEquals "echo bar"
|
||||
call_json_script
|
||||
assertStdoutEquals "echo baz"
|
||||
}
|
||||
|
||||
test_expr_regex_single() {
|
||||
cat >"$JSON_SCRIPT" <<-EOF
|
||||
[
|
||||
[ "if",
|
||||
[ "regex", "VAR", ".ell." ],
|
||||
[ "echo", "bar" ],
|
||||
[ "echo", "baz" ]
|
||||
]
|
||||
]
|
||||
EOF
|
||||
call_json_script "VAR=hello"
|
||||
assertStdoutEquals "echo bar"
|
||||
call_json_script "VAR=.ell."
|
||||
assertStdoutEquals "echo bar"
|
||||
call_json_script
|
||||
assertStdoutEquals "echo baz"
|
||||
call_json_script "VAR="
|
||||
assertStdoutEquals "echo baz"
|
||||
call_json_script "VAR=hell"
|
||||
assertStdoutEquals "echo baz"
|
||||
}
|
||||
|
||||
test_expr_regex_multi() {
|
||||
cat >"$JSON_SCRIPT" <<-EOF
|
||||
[
|
||||
[ "if",
|
||||
[ "regex", "VAR", [ ".ell.", "w.rld" ] ],
|
||||
[ "echo", "bar" ],
|
||||
[ "echo", "baz" ]
|
||||
]
|
||||
]
|
||||
EOF
|
||||
call_json_script "VAR=hello"
|
||||
assertStdoutEquals "echo bar"
|
||||
call_json_script "VAR=world"
|
||||
assertStdoutEquals "echo bar"
|
||||
call_json_script "VAR=.ell."
|
||||
assertStdoutEquals "echo bar"
|
||||
call_json_script "VAR=w.rld"
|
||||
assertStdoutEquals "echo bar"
|
||||
call_json_script
|
||||
assertStdoutEquals "echo baz"
|
||||
call_json_script "VAR="
|
||||
assertStdoutEquals "echo baz"
|
||||
call_json_script "VAR=hell"
|
||||
assertStdoutEquals "echo baz"
|
||||
}
|
||||
|
||||
test_expr_not() {
|
||||
cat >"$JSON_SCRIPT" <<-EOF
|
||||
[
|
||||
[ "if",
|
||||
[ "not", [ "has", "VAR" ] ],
|
||||
[ "echo", "bar" ],
|
||||
[ "echo", "baz" ]
|
||||
]
|
||||
]
|
||||
EOF
|
||||
call_json_script "VAR=foo"
|
||||
assertStdoutEquals "echo baz"
|
||||
call_json_script
|
||||
assertStdoutEquals "echo bar"
|
||||
}
|
||||
|
||||
test_expr_and() {
|
||||
cat >"$JSON_SCRIPT" <<-EOF
|
||||
[
|
||||
[ "if",
|
||||
[ "and", [ "eq", "EQVAR", "eqval" ],
|
||||
[ "regex", "REGEXVAR", "regex..." ]
|
||||
],
|
||||
[ "echo", "bar" ],
|
||||
[ "echo", "baz" ]
|
||||
]
|
||||
]
|
||||
EOF
|
||||
call_json_script "EQVAR=eqval" "REGEXVAR=regexval"
|
||||
assertStdoutEquals "echo bar"
|
||||
call_json_script "EQVAR=foo"
|
||||
assertStdoutEquals "echo baz"
|
||||
call_json_script "REGEXVAR=regex***"
|
||||
assertStdoutEquals "echo baz"
|
||||
call_json_script
|
||||
assertStdoutEquals "echo baz"
|
||||
}
|
||||
|
||||
test_expr_or() {
|
||||
cat >"$JSON_SCRIPT" <<-EOF
|
||||
[
|
||||
[ "if",
|
||||
[ "or", [ "not", [ "eq", "EQVAR", "eqval" ] ],
|
||||
[ "regex", "REGEXVAR", [ "regexva.[0-9]", "regexva.[a-z]" ] ]
|
||||
],
|
||||
[ "echo", "bar" ],
|
||||
[ "echo", "baz" ]
|
||||
]
|
||||
]
|
||||
EOF
|
||||
call_json_script "EQVAR=eqval" "REGEXVAR=regexval1"
|
||||
assertStdoutEquals "echo bar"
|
||||
call_json_script "EQVAR=neq" "REGEXVAR=sxc"
|
||||
assertStdoutEquals "echo bar"
|
||||
call_json_script "REGEXVAR=sxc"
|
||||
assertStdoutEquals "echo bar"
|
||||
call_json_script "EQVAR=foo"
|
||||
assertStdoutEquals "echo bar"
|
||||
call_json_script
|
||||
assertStdoutEquals "echo bar"
|
||||
call_json_script "EQVAR=eqval" "REGEXVAR=regexval"
|
||||
assertStdoutEquals "echo baz"
|
||||
}
|
||||
|
||||
test_expr_isdir() {
|
||||
cat >"$JSON_SCRIPT" <<-EOF
|
||||
[
|
||||
[ "if",
|
||||
[ "isdir", "%VAR%" ],
|
||||
[ "echo", "bar" ],
|
||||
[ "echo", "baz" ]
|
||||
]
|
||||
]
|
||||
EOF
|
||||
call_json_script "VAR=/"
|
||||
assertStdoutEquals "echo bar"
|
||||
call_json_script "VAR=$(mktemp -u)"
|
||||
assertStdoutEquals "echo baz"
|
||||
call_json_script
|
||||
assertStdoutEquals "echo baz"
|
||||
}
|
||||
|
||||
test_cmd_case() {
|
||||
cat >"$JSON_SCRIPT" <<-EOF
|
||||
[
|
||||
[ "case", "CASEVAR", {
|
||||
"0": [ "echo", "foo" ],
|
||||
"1": [
|
||||
[ "echo", "bar" ],
|
||||
[ "echo", "baz" ]
|
||||
],
|
||||
"%VAR%": [ "echo", "quz" ]
|
||||
} ]
|
||||
]
|
||||
EOF
|
||||
call_json_script "CASEVAR=0"
|
||||
assertStdoutEquals "echo foo"
|
||||
call_json_script "CASEVAR=1"
|
||||
assertStdoutEquals "echo bar
|
||||
echo baz"
|
||||
call_json_script "CASEVAR=%VAR%"
|
||||
assertStdoutEquals "echo quz"
|
||||
call_json_script "CASEVAR="
|
||||
assertStdoutEquals ""
|
||||
call_json_script
|
||||
assertStdoutEquals ""
|
||||
call_json_script "CASEVAR=xxx" "VAR=xxx"
|
||||
assertStdoutEquals ""
|
||||
}
|
||||
|
||||
test_cmd_if() {
|
||||
cat >"$JSON_SCRIPT" <<-EOF
|
||||
[
|
||||
[ "if",
|
||||
[ "eq", "VAR", "foo" ],
|
||||
[ "echo", "bar" ],
|
||||
[ "echo", "baz" ]
|
||||
]
|
||||
]
|
||||
EOF
|
||||
call_json_script "VAR=foo"
|
||||
assertStdoutEquals "echo bar"
|
||||
call_json_script "VAR=xxx"
|
||||
assertStdoutEquals "echo baz"
|
||||
}
|
||||
|
||||
test_cmd_cb() {
|
||||
cat >"$JSON_SCRIPT" <<-EOF
|
||||
[
|
||||
[ "exec", "%VAR%", "/%VAS%%%/" ]
|
||||
]
|
||||
EOF
|
||||
call_json_script
|
||||
assertStdoutEquals "exec /%/"
|
||||
call_json_script "VAR="
|
||||
assertStdoutEquals "exec /%/"
|
||||
call_json_script "VAR=qux" "VAS=3"
|
||||
assertStdoutEquals "exec qux /3%/"
|
||||
}
|
||||
|
||||
test_cmd_return() {
|
||||
cat >"$JSON_SCRIPT" <<-EOF
|
||||
[
|
||||
[ "heh", "%HEHVAR%" ],
|
||||
[ "%VAR%", "%VAR%" ],
|
||||
[ "return" ],
|
||||
[ "exec_non_reachable", "Arghhh" ]
|
||||
]
|
||||
EOF
|
||||
call_json_script "HEHVAR=dude" "VAR=ow"
|
||||
assertStdoutEquals "heh dude
|
||||
%VAR% ow"
|
||||
}
|
||||
|
||||
. ./shunit2
|
||||
@@ -16,11 +16,11 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <libubox/uloop.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "uloop.h"
|
||||
#include "runqueue.h"
|
||||
|
||||
static struct runqueue q;
|
||||
|
||||
1067
3P/libubox/examples/shunit2
Normal file
1067
3P/libubox/examples/shunit2
Normal file
File diff suppressed because it is too large
Load Diff
@@ -164,7 +164,7 @@ static int jshn_parse(const char *str)
|
||||
json_object *obj;
|
||||
|
||||
obj = json_tokener_parse(str);
|
||||
if (is_error(obj) || json_object_get_type(obj) != json_type_object) {
|
||||
if (!obj || json_object_get_type(obj) != json_type_object) {
|
||||
fprintf(stderr, "Failed to parse message data\n");
|
||||
return 1;
|
||||
}
|
||||
@@ -179,8 +179,8 @@ static char *get_keys(const char *prefix)
|
||||
{
|
||||
char *keys;
|
||||
|
||||
keys = alloca(var_prefix_len + strlen(prefix) + sizeof("KEYS_") + 1);
|
||||
sprintf(keys, "%sKEYS_%s", var_prefix, prefix);
|
||||
keys = alloca(var_prefix_len + strlen(prefix) + sizeof("K_") + 1);
|
||||
sprintf(keys, "%sK_%s", var_prefix, prefix);
|
||||
return getenv(keys);
|
||||
}
|
||||
|
||||
@@ -188,15 +188,15 @@ static void get_var(const char *prefix, const char **name, char **var, char **ty
|
||||
{
|
||||
char *tmpname, *varname;
|
||||
|
||||
tmpname = alloca(var_prefix_len + strlen(prefix) + 1 + strlen(*name) + 1 + sizeof("TYPE_"));
|
||||
tmpname = alloca(var_prefix_len + strlen(prefix) + 1 + strlen(*name) + 1 + sizeof("T_"));
|
||||
|
||||
sprintf(tmpname, "%s%s_%s", var_prefix, prefix, *name);
|
||||
*var = getenv(tmpname);
|
||||
|
||||
sprintf(tmpname, "%sTYPE_%s_%s", var_prefix, prefix, *name);
|
||||
sprintf(tmpname, "%sT_%s_%s", var_prefix, prefix, *name);
|
||||
*type = getenv(tmpname);
|
||||
|
||||
sprintf(tmpname, "%sNAME_%s_%s", var_prefix, prefix, *name);
|
||||
sprintf(tmpname, "%sN_%s_%s", var_prefix, prefix, *name);
|
||||
varname = getenv(tmpname);
|
||||
if (varname)
|
||||
*name = varname;
|
||||
@@ -258,18 +258,31 @@ static int jshn_format(bool no_newline, bool indent)
|
||||
{
|
||||
json_object *obj;
|
||||
const char *output;
|
||||
char *blobmsg_output = NULL;
|
||||
int ret = -1;
|
||||
|
||||
if (!(obj = json_object_new_object()))
|
||||
return -1;
|
||||
|
||||
jshn_add_objects(obj, "J_V", false);
|
||||
if (!(output = json_object_to_json_string(obj)))
|
||||
goto out;
|
||||
|
||||
obj = json_object_new_object();
|
||||
jshn_add_objects(obj, "JSON_VAR", false);
|
||||
output = json_object_to_json_string(obj);
|
||||
if (indent) {
|
||||
blob_buf_init(&b, 0);
|
||||
blobmsg_add_json_from_string(&b, output);
|
||||
output = blobmsg_format_json_indent(b.head, 1, 0);
|
||||
if (!blobmsg_add_json_from_string(&b, output))
|
||||
goto out;
|
||||
if (!(blobmsg_output = blobmsg_format_json_indent(b.head, 1, 0)))
|
||||
goto out;
|
||||
output = blobmsg_output;
|
||||
}
|
||||
fprintf(stdout, "%s%s", output, no_newline ? "" : "\n");
|
||||
free(blobmsg_output);
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
json_object_put(obj);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usage(const char *progname)
|
||||
|
||||
@@ -32,6 +32,7 @@ struct json_handler {
|
||||
|
||||
static int json_process_expr(struct json_call *call, struct blob_attr *cur);
|
||||
static int json_process_cmd(struct json_call *call, struct blob_attr *cur);
|
||||
static int eval_string(struct json_call *call, struct blob_buf *buf, const char *name, const char *pattern);
|
||||
|
||||
struct json_script_file *
|
||||
json_script_file_from_blobmsg(const char *name, void *data, int len)
|
||||
@@ -333,12 +334,40 @@ static int handle_expr_or(struct json_call *call, struct blob_attr *expr)
|
||||
static int handle_expr_not(struct json_call *call, struct blob_attr *expr)
|
||||
{
|
||||
struct blob_attr *tb[3];
|
||||
int ret;
|
||||
|
||||
json_get_tuple(expr, tb, BLOBMSG_TYPE_ARRAY, 0);
|
||||
if (!tb[1])
|
||||
return -1;
|
||||
|
||||
return json_process_expr(call, tb[1]);
|
||||
ret = json_process_expr(call, tb[1]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return !ret;
|
||||
}
|
||||
|
||||
static int handle_expr_isdir(struct json_call *call, struct blob_attr *expr)
|
||||
{
|
||||
static struct blob_buf b;
|
||||
struct blob_attr *tb[3];
|
||||
const char *pattern, *path;
|
||||
struct stat s;
|
||||
int ret;
|
||||
|
||||
json_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, 0);
|
||||
if (!tb[1] || blobmsg_type(tb[1]) != BLOBMSG_TYPE_STRING)
|
||||
return -1;
|
||||
pattern = blobmsg_data(tb[1]);
|
||||
|
||||
blob_buf_init(&b, 0);
|
||||
ret = eval_string(call, &b, NULL, pattern);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
path = blobmsg_data(blob_data(b.head));
|
||||
ret = stat(path, &s);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
return S_ISDIR(s.st_mode);
|
||||
}
|
||||
|
||||
static const struct json_handler expr[] = {
|
||||
@@ -348,6 +377,7 @@ static const struct json_handler expr[] = {
|
||||
{ "and", handle_expr_and },
|
||||
{ "or", handle_expr_or },
|
||||
{ "not", handle_expr_not },
|
||||
{ "isdir", handle_expr_isdir },
|
||||
};
|
||||
|
||||
static int
|
||||
@@ -416,7 +446,7 @@ static int eval_string(struct json_call *call, struct blob_buf *buf, const char
|
||||
}
|
||||
|
||||
if (cur_var) {
|
||||
if (next > str) {
|
||||
if (end > str) {
|
||||
cur = msg_find_var(call, str);
|
||||
if (!cur)
|
||||
continue;
|
||||
@@ -434,7 +464,7 @@ static int eval_string(struct json_call *call, struct blob_buf *buf, const char
|
||||
cur_len = end - str;
|
||||
}
|
||||
|
||||
dest = blobmsg_realloc_string_buffer(buf, cur_len + 1);
|
||||
dest = blobmsg_realloc_string_buffer(buf, len + cur_len + 1);
|
||||
memcpy(dest + len, cur, cur_len);
|
||||
len += cur_len;
|
||||
}
|
||||
@@ -480,8 +510,8 @@ static int cmd_process_strings(struct json_call *call, struct blob_attr *attr)
|
||||
continue;
|
||||
|
||||
if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) {
|
||||
ctx->handle_error(ctx, "Invalid argument in command", attr);
|
||||
return -1;
|
||||
blobmsg_add_blob(&ctx->buf, cur);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = cmd_add_string(call, blobmsg_data(cur));
|
||||
@@ -537,6 +567,9 @@ static int json_process_cmd(struct json_call *call, struct blob_attr *block)
|
||||
}
|
||||
|
||||
blobmsg_for_each_attr(cur, block, rem) {
|
||||
if (ctx->abort)
|
||||
break;
|
||||
|
||||
switch(blobmsg_type(cur)) {
|
||||
case BLOBMSG_TYPE_STRING:
|
||||
if (!i)
|
||||
@@ -556,7 +589,7 @@ static int json_process_cmd(struct json_call *call, struct blob_attr *block)
|
||||
void json_script_run_file(struct json_script_ctx *ctx, struct json_script_file *file,
|
||||
struct blob_attr *vars)
|
||||
{
|
||||
static __thread unsigned int _seq = 0;
|
||||
static unsigned int _seq = 0;
|
||||
struct json_call call = {
|
||||
.ctx = ctx,
|
||||
.vars = vars,
|
||||
@@ -567,6 +600,8 @@ void json_script_run_file(struct json_script_ctx *ctx, struct json_script_file *
|
||||
if (!call.seq)
|
||||
call.seq = ++_seq;
|
||||
|
||||
ctx->abort = false;
|
||||
|
||||
__json_script_run(&call, file, NULL);
|
||||
}
|
||||
|
||||
@@ -592,8 +627,7 @@ static void __json_script_file_free(struct json_script_file *f)
|
||||
next = f->next;
|
||||
free(f);
|
||||
|
||||
if (next)
|
||||
return __json_script_file_free(next);
|
||||
__json_script_file_free(next);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -28,6 +28,7 @@ struct json_script_ctx {
|
||||
struct blob_buf buf;
|
||||
|
||||
uint32_t run_seq;
|
||||
bool abort;
|
||||
|
||||
/*
|
||||
* handle_command: handle a command that was not recognized by the
|
||||
@@ -99,6 +100,18 @@ void json_script_run(struct json_script_ctx *ctx, const char *filename,
|
||||
|
||||
void json_script_run_file(struct json_script_ctx *ctx, struct json_script_file *file,
|
||||
struct blob_attr *vars);
|
||||
|
||||
/*
|
||||
* json_script_abort - abort current json script run
|
||||
*
|
||||
* to be called from a script context callback
|
||||
*/
|
||||
static inline void
|
||||
json_script_abort(struct json_script_ctx *ctx)
|
||||
{
|
||||
ctx->abort = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* json_script_eval_string - evaluate a string and store the result
|
||||
*
|
||||
|
||||
@@ -5,21 +5,13 @@ PROJECT(uloop C)
|
||||
SET(CMAKE_INSTALL_PREFIX /)
|
||||
|
||||
IF(NOT LUA_CFLAGS)
|
||||
FIND_PROGRAM(PKG_CONFIG pkg-config)
|
||||
IF(PKG_CONFIG)
|
||||
EXECUTE_PROCESS(
|
||||
COMMAND pkg-config --silence-errors --cflags lua5.1
|
||||
OUTPUT_VARIABLE LUA_CFLAGS
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
ENDIF()
|
||||
pkg_search_module(LUA lua5.1 lua-5.1)
|
||||
ENDIF()
|
||||
|
||||
ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -g3 -I.. ${LUA_CFLAGS})
|
||||
LINK_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/..)
|
||||
|
||||
IF(APPLE)
|
||||
ADD_DEFINITIONS(-I/opt/local/include)
|
||||
SET(CMAKE_SHARED_MODULE_CREATE_C_FLAGS "${CMAKE_SHARED_MODULE_CREATE_C_FLAGS} -undefined dynamic_lookup")
|
||||
ENDIF(APPLE)
|
||||
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
uloop.o: ../../../uloop.c \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lua.h \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/luaconf.h \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lnum_config.h \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lualib.h \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lua.h \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lauxlib.h \
|
||||
../../../../uloop.h ../../../../list.h ../../../../list.h
|
||||
Binary file not shown.
@@ -1,8 +0,0 @@
|
||||
uloop.o: ../../../uloop.c \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lua.h \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/luaconf.h \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lnum_config.h \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lualib.h \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lua.h \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lauxlib.h \
|
||||
../../../../uloop.h ../../../../list.h ../../../../list.h
|
||||
Binary file not shown.
@@ -1,8 +0,0 @@
|
||||
uloop.o: ../../../uloop.c \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lua.h \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/luaconf.h \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lnum_config.h \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lualib.h \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lua.h \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lauxlib.h \
|
||||
../../../../uloop.h ../../../../list.h ../../../../list.h
|
||||
Binary file not shown.
@@ -1,8 +0,0 @@
|
||||
uloop.o: ../../../uloop.c \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lua.h \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/luaconf.h \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lnum_config.h \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lualib.h \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lua.h \
|
||||
/home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lauxlib.h \
|
||||
../../../../uloop.h ../../../../list.h ../../../../list.h
|
||||
Binary file not shown.
@@ -43,6 +43,26 @@ struct lua_uloop_process {
|
||||
|
||||
static lua_State *state;
|
||||
|
||||
static void *
|
||||
ul_create_userdata(lua_State *L, size_t size, const luaL_Reg *reg, lua_CFunction gc)
|
||||
{
|
||||
void *ret = lua_newuserdata(L, size);
|
||||
|
||||
memset(ret, 0, size);
|
||||
lua_createtable(L, 0, 2);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_pushcfunction(L, gc);
|
||||
lua_setfield(L, -2, "__gc");
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setmetatable(L, -3);
|
||||
lua_pushvalue(L, -2);
|
||||
luaI_openlib(L, NULL, reg, 1);
|
||||
lua_pushvalue(L, -2);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ul_timer_cb(struct uloop_timeout *t)
|
||||
{
|
||||
struct lua_uloop_timeout *tout = container_of(t, struct lua_uloop_timeout, t);
|
||||
@@ -77,9 +97,9 @@ static int ul_timer_set(lua_State *L)
|
||||
static int ul_timer_free(lua_State *L)
|
||||
{
|
||||
struct lua_uloop_timeout *tout = lua_touserdata(L, 1);
|
||||
|
||||
|
||||
uloop_timeout_cancel(&tout->t);
|
||||
|
||||
|
||||
/* obj.__index.__gc = nil , make sure executing only once*/
|
||||
lua_getfield(L, -1, "__index");
|
||||
lua_pushstring(L, "__gc");
|
||||
@@ -120,22 +140,10 @@ static int ul_timer(lua_State *L)
|
||||
lua_pushvalue(L, -2);
|
||||
ref = luaL_ref(L, -2);
|
||||
|
||||
tout = lua_newuserdata(L, sizeof(*tout));
|
||||
lua_createtable(L, 0, 2);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_pushcfunction(L, ul_timer_free);
|
||||
lua_setfield(L, -2, "__gc");
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setmetatable(L, -3);
|
||||
lua_pushvalue(L, -2);
|
||||
luaI_openlib(L, NULL, timer_m, 1);
|
||||
lua_pushvalue(L, -2);
|
||||
|
||||
memset(tout, 0, sizeof(*tout));
|
||||
|
||||
tout = ul_create_userdata(L, sizeof(*tout), timer_m, ul_timer_free);
|
||||
tout->r = ref;
|
||||
tout->t.cb = ul_timer_cb;
|
||||
|
||||
if (set)
|
||||
uloop_timeout_set(&tout->t, set);
|
||||
|
||||
@@ -181,7 +189,7 @@ static int get_sock_fd(lua_State* L, int idx) {
|
||||
static int ul_ufd_delete(lua_State *L)
|
||||
{
|
||||
struct lua_uloop_fd *ufd = lua_touserdata(L, 1);
|
||||
|
||||
|
||||
uloop_fd_delete(&ufd->fd);
|
||||
|
||||
/* obj.__index.__gc = nil , make sure executing only once*/
|
||||
@@ -238,21 +246,7 @@ static int ul_ufd_add(lua_State *L)
|
||||
fd_ref = luaL_ref(L, -2);
|
||||
lua_pop(L, 1);
|
||||
|
||||
ufd = lua_newuserdata(L, sizeof(*ufd));
|
||||
|
||||
lua_createtable(L, 0, 2);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_pushcfunction(L, ul_ufd_delete);
|
||||
lua_setfield(L, -2, "__gc");
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setmetatable(L, -3);
|
||||
lua_pushvalue(L, -2);
|
||||
luaI_openlib(L, NULL, ufd_m, 1);
|
||||
lua_pushvalue(L, -2);
|
||||
|
||||
memset(ufd, 0, sizeof(*ufd));
|
||||
|
||||
ufd = ul_create_userdata(L, sizeof(*ufd), ufd_m, ul_ufd_delete);
|
||||
ufd->r = ref;
|
||||
ufd->fd.fd = fd;
|
||||
ufd->fd_r = fd_ref;
|
||||
@@ -263,6 +257,32 @@ static int ul_ufd_add(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ul_process_free(lua_State *L)
|
||||
{
|
||||
struct lua_uloop_process *proc = lua_touserdata(L, 1);
|
||||
|
||||
/* obj.__index.__gc = nil , make sure executing only once*/
|
||||
lua_getfield(L, -1, "__index");
|
||||
lua_pushstring(L, "__gc");
|
||||
lua_pushnil(L);
|
||||
lua_settable(L, -3);
|
||||
|
||||
if (proc->r != LUA_NOREF) {
|
||||
uloop_process_delete(&proc->p);
|
||||
|
||||
lua_getglobal(state, "__uloop_cb");
|
||||
luaL_unref(state, -1, proc->r);
|
||||
lua_remove(state, -1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg process_m[] = {
|
||||
{ "delete", ul_process_free },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static void ul_process_cb(struct uloop_process *p, int ret)
|
||||
{
|
||||
struct lua_uloop_process *proc = container_of(p, struct lua_uloop_process, p);
|
||||
@@ -271,6 +291,7 @@ static void ul_process_cb(struct uloop_process *p, int ret)
|
||||
lua_rawgeti(state, -1, proc->r);
|
||||
|
||||
luaL_unref(state, -2, proc->r);
|
||||
proc->r = LUA_NOREF;
|
||||
lua_remove(state, -2);
|
||||
lua_pushinteger(state, ret >> 8);
|
||||
lua_call(state, 1, 0);
|
||||
@@ -330,9 +351,7 @@ static int ul_process(lua_State *L)
|
||||
lua_pushvalue(L, -2);
|
||||
ref = luaL_ref(L, -2);
|
||||
|
||||
proc = lua_newuserdata(L, sizeof(*proc));
|
||||
memset(proc, 0, sizeof(*proc));
|
||||
|
||||
proc = ul_create_userdata(L, sizeof(*proc), process_m, ul_process_free);
|
||||
proc->r = ref;
|
||||
proc->p.pid = pid;
|
||||
proc->p.cb = ul_process_cb;
|
||||
|
||||
508
3P/libubox/md5.c
508
3P/libubox/md5.c
@@ -1,284 +1,336 @@
|
||||
/*
|
||||
* md5.c - Compute MD5 checksum of strings according to the
|
||||
* definition of MD5 in RFC 1321 from April 1992.
|
||||
* Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
|
||||
*
|
||||
* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* Copyright (C) 1995-1999 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2001 Manuel Novoa III
|
||||
* Copyright (C) 2003 Glenn L. McGrath
|
||||
* Copyright (C) 2003 Erik Andersen
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
|
||||
* MD5 Message-Digest Algorithm (RFC 1321).
|
||||
*
|
||||
* Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
|
||||
* Homepage:
|
||||
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
|
||||
*
|
||||
* Author:
|
||||
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
|
||||
*
|
||||
* This software was written by Alexander Peslyak in 2001. No copyright is
|
||||
* claimed, and the software is hereby placed in the public domain.
|
||||
* In case this attempt to disclaim copyright and place the software in the
|
||||
* public domain is deemed null and void, then the software is
|
||||
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
|
||||
* general public under the following terms:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
||||
*
|
||||
* (This is a heavily cut-down "BSD license".)
|
||||
*
|
||||
* This differs from Colin Plumb's older public domain implementation in that
|
||||
* no exactly 32-bit integer data type is required (any 32-bit or wider
|
||||
* unsigned integer data type will do), there's no compile-time endianness
|
||||
* configuration, and the function prototypes match OpenSSL's. No code from
|
||||
* Colin Plumb's implementation has been reused; this comment merely compares
|
||||
* the properties of the two independent implementations.
|
||||
*
|
||||
* The primary goals of this implementation are portability and ease of use.
|
||||
* It is meant to be fast, but not as fast as possible. Some known
|
||||
* optimizations are not included to reduce source code size and avoid
|
||||
* compile-time configuration.
|
||||
*/
|
||||
|
||||
#include "blob.h" /* TODO: better include for bswap_32 compat */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "md5.h"
|
||||
|
||||
/*
|
||||
* The basic MD5 functions.
|
||||
*
|
||||
* F and G are optimized compared to their RFC 1321 definitions for
|
||||
* architectures that lack an AND-NOT instruction, just like in Colin Plumb's
|
||||
* implementation.
|
||||
*/
|
||||
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
|
||||
#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
|
||||
#define H(x, y, z) (((x) ^ (y)) ^ (z))
|
||||
#define H2(x, y, z) ((x) ^ ((y) ^ (z)))
|
||||
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||
|
||||
/*
|
||||
* The MD5 transformation for all four rounds.
|
||||
*/
|
||||
#define STEP(f, a, b, c, d, x, t, s) \
|
||||
(a) += f((b), (c), (d)) + (x) + (t); \
|
||||
(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
|
||||
(a) += (b);
|
||||
|
||||
/*
|
||||
* SET reads 4 input bytes in little-endian byte order and stores them
|
||||
* in a properly aligned word in host byte order.
|
||||
*/
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define SWAP_LE32(x) (x)
|
||||
#define SET(n) \
|
||||
(*(uint32_t *)&ptr[(n) * 4])
|
||||
#define GET(n) \
|
||||
SET(n)
|
||||
#else
|
||||
#define SWAP_LE32(x) bswap_32(x)
|
||||
#define SET(n) \
|
||||
(block[(n)] = \
|
||||
(uint32_t)ptr[(n) * 4] | \
|
||||
((uint32_t)ptr[(n) * 4 + 1] << 8) | \
|
||||
((uint32_t)ptr[(n) * 4 + 2] << 16) | \
|
||||
((uint32_t)ptr[(n) * 4 + 3] << 24))
|
||||
#define GET(n) \
|
||||
(block[(n)])
|
||||
#endif
|
||||
|
||||
/* Initialize structure containing state of computation.
|
||||
* (RFC 1321, 3.3: Step 3)
|
||||
/*
|
||||
* This processes one or more 64-byte data blocks, but does NOT update
|
||||
* the bit counters. There are no alignment requirements.
|
||||
*/
|
||||
static const void *body(md5_ctx_t *ctx, const void *data, unsigned long size)
|
||||
{
|
||||
const unsigned char *ptr;
|
||||
uint32_t a, b, c, d;
|
||||
uint32_t saved_a, saved_b, saved_c, saved_d;
|
||||
#if __BYTE_ORDER != __LITTLE_ENDIAN
|
||||
uint32_t block[16];
|
||||
#endif
|
||||
|
||||
ptr = (const unsigned char *)data;
|
||||
|
||||
a = ctx->a;
|
||||
b = ctx->b;
|
||||
c = ctx->c;
|
||||
d = ctx->d;
|
||||
|
||||
do {
|
||||
saved_a = a;
|
||||
saved_b = b;
|
||||
saved_c = c;
|
||||
saved_d = d;
|
||||
|
||||
/* Round 1 */
|
||||
STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
|
||||
STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
|
||||
STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
|
||||
STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
|
||||
STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
|
||||
STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
|
||||
STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
|
||||
STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
|
||||
STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
|
||||
STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
|
||||
STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
|
||||
STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
|
||||
STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
|
||||
STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
|
||||
STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
|
||||
STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
|
||||
|
||||
/* Round 2 */
|
||||
STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
|
||||
STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
|
||||
STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
|
||||
STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
|
||||
STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
|
||||
STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
|
||||
STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
|
||||
STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
|
||||
STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
|
||||
STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
|
||||
STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
|
||||
STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
|
||||
STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
|
||||
STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
|
||||
STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
|
||||
STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
|
||||
|
||||
/* Round 3 */
|
||||
STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
|
||||
STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
|
||||
STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
|
||||
STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
|
||||
STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
|
||||
STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
|
||||
STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
|
||||
STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
|
||||
STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
|
||||
STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
|
||||
STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
|
||||
STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
|
||||
STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
|
||||
STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
|
||||
STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
|
||||
STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
|
||||
|
||||
/* Round 4 */
|
||||
STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
|
||||
STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
|
||||
STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
|
||||
STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
|
||||
STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
|
||||
STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
|
||||
STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
|
||||
STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
|
||||
STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
|
||||
STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
|
||||
STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
|
||||
STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
|
||||
STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
|
||||
STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
|
||||
STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
|
||||
STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
|
||||
|
||||
a += saved_a;
|
||||
b += saved_b;
|
||||
c += saved_c;
|
||||
d += saved_d;
|
||||
|
||||
ptr += 64;
|
||||
} while (size -= 64);
|
||||
|
||||
ctx->a = a;
|
||||
ctx->b = b;
|
||||
ctx->c = c;
|
||||
ctx->d = d;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void md5_begin(md5_ctx_t *ctx)
|
||||
{
|
||||
ctx->A = 0x67452301;
|
||||
ctx->B = 0xefcdab89;
|
||||
ctx->C = 0x98badcfe;
|
||||
ctx->D = 0x10325476;
|
||||
ctx->a = 0x67452301;
|
||||
ctx->b = 0xefcdab89;
|
||||
ctx->c = 0x98badcfe;
|
||||
ctx->d = 0x10325476;
|
||||
|
||||
ctx->total = 0;
|
||||
ctx->buflen = 0;
|
||||
ctx->lo = 0;
|
||||
ctx->hi = 0;
|
||||
}
|
||||
|
||||
/* These are the four functions used in the four steps of the MD5 algorithm
|
||||
* and defined in the RFC 1321. The first function is a little bit optimized
|
||||
* (as found in Colin Plumbs public domain implementation).
|
||||
* #define FF(b, c, d) ((b & c) | (~b & d))
|
||||
*/
|
||||
# define FF(b, c, d) (d ^ (b & (c ^ d)))
|
||||
# define FG(b, c, d) FF (d, b, c)
|
||||
# define FH(b, c, d) (b ^ c ^ d)
|
||||
# define FI(b, c, d) (c ^ (b | ~d))
|
||||
|
||||
/* Hash a single block, 64 bytes long and 4-byte aligned. */
|
||||
static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
|
||||
void md5_hash(const void *data, size_t size, md5_ctx_t *ctx)
|
||||
{
|
||||
uint32_t correct_words[16];
|
||||
const uint32_t *words = buffer;
|
||||
uint32_t saved_lo;
|
||||
unsigned long used, available;
|
||||
|
||||
static const uint32_t C_array[] = {
|
||||
/* round 1 */
|
||||
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
|
||||
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
||||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
|
||||
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
|
||||
/* round 2 */
|
||||
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
|
||||
0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8,
|
||||
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
|
||||
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
|
||||
/* round 3 */
|
||||
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
|
||||
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
|
||||
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
|
||||
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
|
||||
/* round 4 */
|
||||
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
|
||||
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
|
||||
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
|
||||
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
|
||||
};
|
||||
saved_lo = ctx->lo;
|
||||
if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
|
||||
ctx->hi++;
|
||||
ctx->hi += size >> 29;
|
||||
|
||||
static const char P_array[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
|
||||
1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */
|
||||
5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */
|
||||
0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */
|
||||
};
|
||||
used = saved_lo & 0x3f;
|
||||
|
||||
static const char S_array[] = {
|
||||
7, 12, 17, 22,
|
||||
5, 9, 14, 20,
|
||||
4, 11, 16, 23,
|
||||
6, 10, 15, 21
|
||||
};
|
||||
if (used) {
|
||||
available = 64 - used;
|
||||
|
||||
uint32_t A = ctx->A;
|
||||
uint32_t B = ctx->B;
|
||||
uint32_t C = ctx->C;
|
||||
uint32_t D = ctx->D;
|
||||
|
||||
uint32_t *cwp = correct_words;
|
||||
|
||||
# define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
|
||||
|
||||
const uint32_t *pc;
|
||||
const char *pp;
|
||||
const char *ps;
|
||||
int i;
|
||||
uint32_t temp;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
cwp[i] = SWAP_LE32(words[i]);
|
||||
}
|
||||
|
||||
pc = C_array;
|
||||
pp = P_array;
|
||||
ps = S_array;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
temp = A + FF(B, C, D) + cwp[(int) (*pp++)] + *pc++;
|
||||
CYCLIC(temp, ps[i & 3]);
|
||||
temp += B;
|
||||
A = D;
|
||||
D = C;
|
||||
C = B;
|
||||
B = temp;
|
||||
}
|
||||
|
||||
ps += 4;
|
||||
for (i = 0; i < 16; i++) {
|
||||
temp = A + FG(B, C, D) + cwp[(int) (*pp++)] + *pc++;
|
||||
CYCLIC(temp, ps[i & 3]);
|
||||
temp += B;
|
||||
A = D;
|
||||
D = C;
|
||||
C = B;
|
||||
B = temp;
|
||||
}
|
||||
ps += 4;
|
||||
for (i = 0; i < 16; i++) {
|
||||
temp = A + FH(B, C, D) + cwp[(int) (*pp++)] + *pc++;
|
||||
CYCLIC(temp, ps[i & 3]);
|
||||
temp += B;
|
||||
A = D;
|
||||
D = C;
|
||||
C = B;
|
||||
B = temp;
|
||||
}
|
||||
ps += 4;
|
||||
for (i = 0; i < 16; i++) {
|
||||
temp = A + FI(B, C, D) + cwp[(int) (*pp++)] + *pc++;
|
||||
CYCLIC(temp, ps[i & 3]);
|
||||
temp += B;
|
||||
A = D;
|
||||
D = C;
|
||||
C = B;
|
||||
B = temp;
|
||||
}
|
||||
|
||||
|
||||
ctx->A += A;
|
||||
ctx->B += B;
|
||||
ctx->C += C;
|
||||
ctx->D += D;
|
||||
}
|
||||
|
||||
/* Feed data through a temporary buffer to call md5_hash_aligned_block()
|
||||
* with chunks of data that are 4-byte aligned and a multiple of 64 bytes.
|
||||
* This function's internal buffer remembers previous data until it has 64
|
||||
* bytes worth to pass on. Call md5_end() to flush this buffer. */
|
||||
|
||||
void md5_hash(const void *buffer, size_t len, md5_ctx_t *ctx)
|
||||
{
|
||||
char *buf = (char *)buffer;
|
||||
|
||||
/* RFC 1321 specifies the possible length of the file up to 2^64 bits,
|
||||
* Here we only track the number of bytes. */
|
||||
|
||||
ctx->total += len;
|
||||
|
||||
// Process all input.
|
||||
|
||||
while (len) {
|
||||
unsigned i = 64 - ctx->buflen;
|
||||
|
||||
// Copy data into aligned buffer.
|
||||
|
||||
if (i > len)
|
||||
i = len;
|
||||
memcpy(ctx->buffer + ctx->buflen, buf, i);
|
||||
len -= i;
|
||||
ctx->buflen += i;
|
||||
buf += i;
|
||||
|
||||
// When buffer fills up, process it.
|
||||
|
||||
if (ctx->buflen == 64) {
|
||||
md5_hash_block(ctx->buffer, ctx);
|
||||
ctx->buflen = 0;
|
||||
if (size < available) {
|
||||
memcpy(&ctx->buffer[used], data, size);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&ctx->buffer[used], data, available);
|
||||
data = (const unsigned char *)data + available;
|
||||
size -= available;
|
||||
body(ctx, ctx->buffer, 64);
|
||||
}
|
||||
|
||||
if (size >= 64) {
|
||||
data = body(ctx, data, size & ~((size_t) 0x3f));
|
||||
size &= 0x3f;
|
||||
}
|
||||
|
||||
memcpy(ctx->buffer, data, size);
|
||||
}
|
||||
|
||||
/* Process the remaining bytes in the buffer and put result from CTX
|
||||
* in first 16 bytes following RESBUF. The result is always in little
|
||||
* endian byte order, so that a byte-wise output yields to the wanted
|
||||
* ASCII representation of the message digest.
|
||||
*
|
||||
* IMPORTANT: On some systems it is required that RESBUF is correctly
|
||||
* aligned for a 32 bits value.
|
||||
*/
|
||||
void md5_end(void *resbuf, md5_ctx_t *ctx)
|
||||
{
|
||||
char *buf = ctx->buffer;
|
||||
int i;
|
||||
unsigned char *result = resbuf;
|
||||
unsigned long used, available;
|
||||
|
||||
/* Pad data to block size. */
|
||||
used = ctx->lo & 0x3f;
|
||||
|
||||
buf[ctx->buflen++] = 0x80;
|
||||
memset(buf + ctx->buflen, 0, 128 - ctx->buflen);
|
||||
ctx->buffer[used++] = 0x80;
|
||||
|
||||
/* Put the 64-bit file length in *bits* at the end of the buffer. */
|
||||
ctx->total <<= 3;
|
||||
if (ctx->buflen > 56)
|
||||
buf += 64;
|
||||
available = 64 - used;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
buf[56 + i] = ctx->total >> (i*8);
|
||||
if (available < 8) {
|
||||
memset(&ctx->buffer[used], 0, available);
|
||||
body(ctx, ctx->buffer, 64);
|
||||
used = 0;
|
||||
available = 64;
|
||||
}
|
||||
|
||||
/* Process last bytes. */
|
||||
if (buf != ctx->buffer)
|
||||
md5_hash_block(ctx->buffer, ctx);
|
||||
md5_hash_block(buf, ctx);
|
||||
memset(&ctx->buffer[used], 0, available - 8);
|
||||
|
||||
/* Put result from CTX in first 16 bytes following RESBUF. The result is
|
||||
* always in little endian byte order, so that a byte-wise output yields
|
||||
* to the wanted ASCII representation of the message digest.
|
||||
*
|
||||
* IMPORTANT: On some systems it is required that RESBUF is correctly
|
||||
* aligned for a 32 bits value.
|
||||
*/
|
||||
((uint32_t *) resbuf)[0] = SWAP_LE32(ctx->A);
|
||||
((uint32_t *) resbuf)[1] = SWAP_LE32(ctx->B);
|
||||
((uint32_t *) resbuf)[2] = SWAP_LE32(ctx->C);
|
||||
((uint32_t *) resbuf)[3] = SWAP_LE32(ctx->D);
|
||||
ctx->lo <<= 3;
|
||||
ctx->buffer[56] = ctx->lo;
|
||||
ctx->buffer[57] = ctx->lo >> 8;
|
||||
ctx->buffer[58] = ctx->lo >> 16;
|
||||
ctx->buffer[59] = ctx->lo >> 24;
|
||||
ctx->buffer[60] = ctx->hi;
|
||||
ctx->buffer[61] = ctx->hi >> 8;
|
||||
ctx->buffer[62] = ctx->hi >> 16;
|
||||
ctx->buffer[63] = ctx->hi >> 24;
|
||||
|
||||
body(ctx, ctx->buffer, 64);
|
||||
|
||||
result[0] = ctx->a;
|
||||
result[1] = ctx->a >> 8;
|
||||
result[2] = ctx->a >> 16;
|
||||
result[3] = ctx->a >> 24;
|
||||
result[4] = ctx->b;
|
||||
result[5] = ctx->b >> 8;
|
||||
result[6] = ctx->b >> 16;
|
||||
result[7] = ctx->b >> 24;
|
||||
result[8] = ctx->c;
|
||||
result[9] = ctx->c >> 8;
|
||||
result[10] = ctx->c >> 16;
|
||||
result[11] = ctx->c >> 24;
|
||||
result[12] = ctx->d;
|
||||
result[13] = ctx->d >> 8;
|
||||
result[14] = ctx->d >> 16;
|
||||
result[15] = ctx->d >> 24;
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
}
|
||||
|
||||
int md5sum(char *file, uint32_t *md5)
|
||||
int md5sum(char *file, void *md5_buf)
|
||||
{
|
||||
char buf[256];
|
||||
md5_ctx_t ctx;
|
||||
int len, fd;
|
||||
int ret = 0;
|
||||
FILE *f;
|
||||
|
||||
memset(md5, 0, sizeof(*md5) * 4);
|
||||
|
||||
fd = open(file, O_RDONLY);
|
||||
if (fd < 0)
|
||||
f = fopen(file, "r");
|
||||
if (!f)
|
||||
return -1;
|
||||
|
||||
md5_begin(&ctx);
|
||||
do {
|
||||
len = read(fd, buf, sizeof(buf));
|
||||
if (len < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
int len = fread(buf, 1, sizeof(buf), f);
|
||||
if (!len)
|
||||
break;
|
||||
|
||||
md5_hash(buf, len, &ctx);
|
||||
ret += len;
|
||||
} while(1);
|
||||
|
||||
md5_end(md5, &ctx);
|
||||
out:
|
||||
close(fd);
|
||||
md5_end(md5_buf, &ctx);
|
||||
fclose(f);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1,36 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
|
||||
* Copyright (C) 2013 John Crispin <blogic@openwrt.org>
|
||||
* Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1
|
||||
* as published by the Free Software Foundation
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
|
||||
* MD5 Message-Digest Algorithm (RFC 1321).
|
||||
*
|
||||
* Homepage:
|
||||
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
|
||||
*
|
||||
* Author:
|
||||
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
|
||||
*
|
||||
* This software was written by Alexander Peslyak in 2001. No copyright is
|
||||
* claimed, and the software is hereby placed in the public domain.
|
||||
* In case this attempt to disclaim copyright and place the software in the
|
||||
* public domain is deemed null and void, then the software is
|
||||
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
|
||||
* general public under the following terms:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
||||
*
|
||||
* See md5.c for more information.
|
||||
*/
|
||||
|
||||
#ifndef __PROCD_MD5_H
|
||||
#define __PROCD_MD5_H
|
||||
#ifndef _LIBUBOX_MD5_H
|
||||
#define _LIBUBOX_MD5_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct md5_ctx {
|
||||
uint32_t A;
|
||||
uint32_t B;
|
||||
uint32_t C;
|
||||
uint32_t D;
|
||||
uint64_t total;
|
||||
uint32_t buflen;
|
||||
char buffer[128];
|
||||
uint32_t lo, hi;
|
||||
uint32_t a, b, c, d;
|
||||
unsigned char buffer[64];
|
||||
} md5_ctx_t;
|
||||
|
||||
void md5_begin(md5_ctx_t *ctx);
|
||||
void md5_hash(const void *data, size_t length, md5_ctx_t *ctx);
|
||||
void md5_end(void *resbuf, md5_ctx_t *ctx);
|
||||
int md5sum(char *file, uint32_t *md5);
|
||||
extern void md5_begin(md5_ctx_t *ctx);
|
||||
extern void md5_hash(const void *data, size_t length, md5_ctx_t *ctx);
|
||||
extern void md5_end(void *resbuf, md5_ctx_t *ctx);
|
||||
int md5sum(char *file, void *md5_buf);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -42,7 +42,7 @@ _json_inc() {
|
||||
# var=$1
|
||||
# dest=$2
|
||||
|
||||
eval "${JSON_PREFIX}$1=\$(( \${${JSON_PREFIX}$1:-0} + 1))${2:+; $2=\"\$${JSON_PREFIX}$1\"}"
|
||||
let "${JSON_PREFIX}$1 += 1" "$2 = ${JSON_PREFIX}$1"
|
||||
}
|
||||
|
||||
_json_add_generic() {
|
||||
@@ -52,20 +52,18 @@ _json_add_generic() {
|
||||
# cur=$4
|
||||
|
||||
local var
|
||||
if [ "${4%%[0-9]*}" = "JSON_ARRAY" ]; then
|
||||
_json_inc "SEQ_$4" var
|
||||
if [ "${4%%[0-9]*}" = "J_A" ]; then
|
||||
_json_inc "S_$4" var
|
||||
else
|
||||
local name="${2//[^a-zA-Z0-9_]/_}"
|
||||
[[ "$name" == "$2" ]] || export -- "${JSON_PREFIX}NAME_${4}_${name}=$2"
|
||||
var="$name"
|
||||
var="${2//[^a-zA-Z0-9_]/_}"
|
||||
[[ "$var" == "$2" ]] || export -- "${JSON_PREFIX}N_${4}_${var}=$2"
|
||||
fi
|
||||
|
||||
local cur_var=
|
||||
export -- \
|
||||
"${JSON_PREFIX}${4}_$var=$3" \
|
||||
"${JSON_PREFIX}TYPE_${4}_$var=$1"
|
||||
"${JSON_PREFIX}T_${4}_$var=$1"
|
||||
_jshn_append "JSON_UNSET" "${4}_$var"
|
||||
_jshn_append "KEYS_$4" "$var"
|
||||
_jshn_append "K_$4" "$var"
|
||||
}
|
||||
|
||||
_json_add_table() {
|
||||
@@ -77,10 +75,10 @@ _json_add_table() {
|
||||
_json_get_var cur JSON_CUR
|
||||
_json_inc JSON_SEQ seq
|
||||
|
||||
local table="JSON_$3$seq"
|
||||
_json_set_var "UP_$table" "$cur"
|
||||
export -- "${JSON_PREFIX}KEYS_$table="
|
||||
unset "${JSON_PREFIX}SEQ_$table"
|
||||
local table="J_$3$seq"
|
||||
_json_set_var "U_$table" "$cur"
|
||||
export -- "${JSON_PREFIX}K_$table="
|
||||
unset "${JSON_PREFIX}S_$table"
|
||||
_json_set_var JSON_CUR "$table"
|
||||
_jshn_append "JSON_UNSET" "$table"
|
||||
|
||||
@@ -91,7 +89,7 @@ _json_close_table() {
|
||||
local _s_cur
|
||||
|
||||
_json_get_var _s_cur JSON_CUR
|
||||
_json_get_var "${JSON_PREFIX}JSON_CUR" "UP_$_s_cur"
|
||||
_json_get_var "${JSON_PREFIX}JSON_CUR" "U_$_s_cur"
|
||||
}
|
||||
|
||||
json_set_namespace() {
|
||||
@@ -106,13 +104,13 @@ json_cleanup() {
|
||||
local unset tmp
|
||||
|
||||
_json_get_var unset JSON_UNSET
|
||||
for tmp in $unset JSON_VAR; do
|
||||
for tmp in $unset J_V; do
|
||||
unset \
|
||||
${JSON_PREFIX}UP_$tmp \
|
||||
${JSON_PREFIX}KEYS_$tmp \
|
||||
${JSON_PREFIX}SEQ_$tmp \
|
||||
${JSON_PREFIX}TYPE_$tmp \
|
||||
${JSON_PREFIX}NAME_$tmp \
|
||||
${JSON_PREFIX}U_$tmp \
|
||||
${JSON_PREFIX}K_$tmp \
|
||||
${JSON_PREFIX}S_$tmp \
|
||||
${JSON_PREFIX}T_$tmp \
|
||||
${JSON_PREFIX}N_$tmp \
|
||||
${JSON_PREFIX}$tmp
|
||||
done
|
||||
|
||||
@@ -124,15 +122,14 @@ json_cleanup() {
|
||||
|
||||
json_init() {
|
||||
json_cleanup
|
||||
export -n ${JSON_PREFIX}JSON_SEQ=0
|
||||
export -- \
|
||||
${JSON_PREFIX}JSON_SEQ=0 \
|
||||
${JSON_PREFIX}JSON_CUR="JSON_VAR" \
|
||||
${JSON_PREFIX}KEYS_JSON_VAR= \
|
||||
${JSON_PREFIX}TYPE_JSON_VAR=
|
||||
${JSON_PREFIX}JSON_CUR="J_V" \
|
||||
${JSON_PREFIX}K_J_V=
|
||||
}
|
||||
|
||||
json_add_object() {
|
||||
_json_add_table "$1" object TABLE
|
||||
_json_add_table "$1" object T
|
||||
}
|
||||
|
||||
json_close_object() {
|
||||
@@ -140,7 +137,7 @@ json_close_object() {
|
||||
}
|
||||
|
||||
json_add_array() {
|
||||
_json_add_table "$1" array ARRAY
|
||||
_json_add_table "$1" array A
|
||||
}
|
||||
|
||||
json_close_array() {
|
||||
@@ -186,7 +183,7 @@ json_get_type() {
|
||||
local __cur
|
||||
|
||||
_json_get_var __cur JSON_CUR
|
||||
local __var="${JSON_PREFIX}TYPE_${__cur}_${2//[^a-zA-Z0-9_]/_}"
|
||||
local __var="${JSON_PREFIX}T_${__cur}_${2//[^a-zA-Z0-9_]/_}"
|
||||
eval "export -- \"$__dest=\${$__var}\"; [ -n \"\${$__var+x}\" ]"
|
||||
}
|
||||
|
||||
@@ -199,7 +196,7 @@ json_get_keys() {
|
||||
else
|
||||
_json_get_var _tbl_cur JSON_CUR
|
||||
fi
|
||||
local __var="${JSON_PREFIX}KEYS_${_tbl_cur}"
|
||||
local __var="${JSON_PREFIX}K_${_tbl_cur}"
|
||||
eval "export -- \"$__dest=\${$__var}\"; [ -n \"\${$__var+x}\" ]"
|
||||
}
|
||||
|
||||
@@ -252,12 +249,12 @@ json_select() {
|
||||
local cur
|
||||
|
||||
[ -z "$1" ] && {
|
||||
_json_set_var JSON_CUR "JSON_VAR"
|
||||
_json_set_var JSON_CUR "J_V"
|
||||
return 0
|
||||
}
|
||||
[[ "$1" == ".." ]] && {
|
||||
_json_get_var cur JSON_CUR
|
||||
_json_get_var cur "UP_$cur"
|
||||
_json_get_var cur "U_$cur"
|
||||
_json_set_var JSON_CUR "$cur"
|
||||
return 0
|
||||
}
|
||||
|
||||
173
3P/libubox/ulog.c
Normal file
173
3P/libubox/ulog.c
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* ulog - simple logging functions
|
||||
*
|
||||
* Copyright (C) 2015 Jo-Philipp Wich <jow@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ulog.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
static int _ulog_channels = -1;
|
||||
static int _ulog_facility = -1;
|
||||
static int _ulog_threshold = LOG_DEBUG;
|
||||
static int _ulog_initialized = 0;
|
||||
static const char *_ulog_ident = NULL;
|
||||
|
||||
static const char *ulog_default_ident(void)
|
||||
{
|
||||
FILE *self;
|
||||
static char line[64];
|
||||
char *p = NULL;
|
||||
|
||||
if ((self = fopen("/proc/self/status", "r")) != NULL) {
|
||||
while (fgets(line, sizeof(line), self)) {
|
||||
if (!strncmp(line, "Name:", 5)) {
|
||||
strtok(line, "\t\n");
|
||||
p = strtok(NULL, "\t\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(self);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static void ulog_defaults(void)
|
||||
{
|
||||
char *env;
|
||||
|
||||
if (_ulog_initialized)
|
||||
return;
|
||||
|
||||
env = getenv("PREINIT");
|
||||
|
||||
if (_ulog_channels < 0) {
|
||||
if (env && !strcmp(env, "1"))
|
||||
_ulog_channels = ULOG_KMSG;
|
||||
else if (isatty(1))
|
||||
_ulog_channels = ULOG_STDIO;
|
||||
else
|
||||
_ulog_channels = ULOG_SYSLOG;
|
||||
}
|
||||
|
||||
if (_ulog_facility < 0) {
|
||||
if (env && !strcmp(env, "1"))
|
||||
_ulog_facility = LOG_DAEMON;
|
||||
else if (isatty(1))
|
||||
_ulog_facility = LOG_USER;
|
||||
else
|
||||
_ulog_facility = LOG_DAEMON;
|
||||
}
|
||||
|
||||
if (_ulog_ident == NULL && _ulog_channels != ULOG_STDIO)
|
||||
_ulog_ident = ulog_default_ident();
|
||||
|
||||
if (_ulog_channels & ULOG_SYSLOG)
|
||||
openlog(_ulog_ident, 0, _ulog_facility);
|
||||
|
||||
_ulog_initialized = 1;
|
||||
}
|
||||
|
||||
static void ulog_kmsg(int priority, const char *fmt, va_list ap)
|
||||
{
|
||||
FILE *kmsg;
|
||||
|
||||
if ((kmsg = fopen("/dev/kmsg", "r+")) != NULL) {
|
||||
fprintf(kmsg, "<%u>", priority);
|
||||
|
||||
if (_ulog_ident)
|
||||
fprintf(kmsg, "%s: ", _ulog_ident);
|
||||
|
||||
vfprintf(kmsg, fmt, ap);
|
||||
fclose(kmsg);
|
||||
}
|
||||
}
|
||||
|
||||
static void ulog_stdio(int priority, const char *fmt, va_list ap)
|
||||
{
|
||||
FILE *out = stderr;
|
||||
|
||||
if (_ulog_ident)
|
||||
fprintf(out, "%s: ", _ulog_ident);
|
||||
|
||||
vfprintf(out, fmt, ap);
|
||||
}
|
||||
|
||||
static void ulog_syslog(int priority, const char *fmt, va_list ap)
|
||||
{
|
||||
vsyslog(priority, fmt, ap);
|
||||
}
|
||||
|
||||
void ulog_open(int channels, int facility, const char *ident)
|
||||
{
|
||||
ulog_close();
|
||||
|
||||
_ulog_channels = channels;
|
||||
_ulog_facility = facility;
|
||||
_ulog_ident = ident;
|
||||
}
|
||||
|
||||
void ulog_close(void)
|
||||
{
|
||||
if (!_ulog_initialized)
|
||||
return;
|
||||
|
||||
if (_ulog_channels & ULOG_SYSLOG)
|
||||
closelog();
|
||||
|
||||
_ulog_initialized = 0;
|
||||
}
|
||||
|
||||
void ulog_threshold(int threshold)
|
||||
{
|
||||
_ulog_threshold = threshold;
|
||||
}
|
||||
|
||||
void ulog(int priority, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (priority > _ulog_threshold)
|
||||
return;
|
||||
|
||||
ulog_defaults();
|
||||
|
||||
if (_ulog_channels & ULOG_KMSG)
|
||||
{
|
||||
va_start(ap, fmt);
|
||||
ulog_kmsg(priority, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
if (_ulog_channels & ULOG_STDIO)
|
||||
{
|
||||
va_start(ap, fmt);
|
||||
ulog_stdio(priority, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
if (_ulog_channels & ULOG_SYSLOG)
|
||||
{
|
||||
va_start(ap, fmt);
|
||||
ulog_syslog(priority, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
42
3P/libubox/ulog.h
Normal file
42
3P/libubox/ulog.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* ulog - simple logging functions
|
||||
*
|
||||
* Copyright (C) 2015 Jo-Philipp Wich <jow@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBUBOX_ULOG_H
|
||||
#define __LIBUBOX_ULOG_H
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
enum {
|
||||
ULOG_KMSG = (1 << 0),
|
||||
ULOG_SYSLOG = (1 << 1),
|
||||
ULOG_STDIO = (1 << 2)
|
||||
};
|
||||
|
||||
void ulog_open(int channels, int facility, const char *ident);
|
||||
void ulog_close(void);
|
||||
|
||||
void ulog_threshold(int threshold);
|
||||
|
||||
void ulog(int priority, const char *fmt, ...);
|
||||
|
||||
#define ULOG_INFO(fmt, ...) ulog(LOG_INFO, fmt, ## __VA_ARGS__)
|
||||
#define ULOG_NOTE(fmt, ...) ulog(LOG_NOTICE, fmt, ## __VA_ARGS__)
|
||||
#define ULOG_WARN(fmt, ...) ulog(LOG_WARNING, fmt, ## __VA_ARGS__)
|
||||
#define ULOG_ERR(fmt, ...) ulog(LOG_ERR, fmt, ## __VA_ARGS__)
|
||||
|
||||
#endif
|
||||
@@ -53,13 +53,12 @@ static __thread struct uloop_fd_stack *fd_stack = NULL;
|
||||
|
||||
#define ULOOP_MAX_EVENTS 10
|
||||
|
||||
static __thread struct list_head timeouts = {0};
|
||||
static __thread struct list_head processes = {0};
|
||||
static __thread struct list_head timeouts = LIST_HEAD_INIT(timeouts);
|
||||
static __thread struct list_head processes = LIST_HEAD_INIT(processes);
|
||||
|
||||
static __thread int poll_fd = -1;
|
||||
__thread bool uloop_cancelled = false;
|
||||
__thread bool uloop_handle_sigchld = true;
|
||||
static __thread bool do_sigchld = false;
|
||||
__thread static bool do_sigchld = false;
|
||||
|
||||
static __thread struct uloop_fd_event cur_fds[ULOOP_MAX_EVENTS];
|
||||
static __thread int cur_fd, cur_nfds;
|
||||
@@ -213,10 +212,7 @@ int uloop_init(void)
|
||||
{
|
||||
if (poll_fd >= 0)
|
||||
return 0;
|
||||
|
||||
if ((timeouts.next == 0) && (timeouts.prev == 0)) INIT_LIST_HEAD (&timeouts);
|
||||
if ((processes.next == 0) && (processes.prev == 0)) INIT_LIST_HEAD (&processes);
|
||||
|
||||
|
||||
poll_fd = epoll_create(32);
|
||||
if (poll_fd < 0)
|
||||
return -1;
|
||||
@@ -457,14 +453,14 @@ int uloop_timeout_set(struct uloop_timeout *timeout, int msecs)
|
||||
if (timeout->pending)
|
||||
uloop_timeout_cancel(timeout);
|
||||
|
||||
uloop_gettime(&timeout->time);
|
||||
uloop_gettime(time);
|
||||
|
||||
time->tv_sec += msecs / 1000;
|
||||
time->tv_usec += (msecs % 1000) * 1000;
|
||||
|
||||
if (time->tv_usec > 1000000) {
|
||||
time->tv_sec++;
|
||||
time->tv_usec %= 1000000;
|
||||
time->tv_usec -= 1000000;
|
||||
}
|
||||
|
||||
return uloop_timeout_add(timeout);
|
||||
@@ -562,31 +558,61 @@ static void uloop_sigchld(int signo)
|
||||
do_sigchld = true;
|
||||
}
|
||||
|
||||
static void uloop_setup_signals(bool add)
|
||||
static void uloop_install_handler(int signum, void (*handler)(int), struct sigaction* old, bool add)
|
||||
{
|
||||
static struct sigaction old_sigint, old_sigchld;
|
||||
struct sigaction s;
|
||||
struct sigaction *act;
|
||||
|
||||
memset(&s, 0, sizeof(struct sigaction));
|
||||
act = NULL;
|
||||
sigaction(signum, NULL, &s);
|
||||
|
||||
if (add) {
|
||||
s.sa_handler = uloop_handle_sigint;
|
||||
s.sa_flags = 0;
|
||||
} else {
|
||||
s = old_sigint;
|
||||
if (s.sa_handler == SIG_DFL) { /* Do not override existing custom signal handlers */
|
||||
memcpy(old, &s, sizeof(struct sigaction));
|
||||
s.sa_handler = handler;
|
||||
s.sa_flags = 0;
|
||||
act = &s;
|
||||
}
|
||||
}
|
||||
else if (s.sa_handler == handler) { /* Do not restore if someone modified our handler */
|
||||
act = old;
|
||||
}
|
||||
|
||||
sigaction(SIGINT, &s, &old_sigint);
|
||||
if (act != NULL)
|
||||
sigaction(signum, act, NULL);
|
||||
}
|
||||
|
||||
if (!uloop_handle_sigchld)
|
||||
return;
|
||||
static void uloop_ignore_signal(int signum, bool ignore)
|
||||
{
|
||||
struct sigaction s;
|
||||
void *new_handler = NULL;
|
||||
|
||||
if (add)
|
||||
s.sa_handler = uloop_sigchld;
|
||||
else
|
||||
s = old_sigchld;
|
||||
sigaction(signum, NULL, &s);
|
||||
|
||||
sigaction(SIGCHLD, &s, &old_sigchld);
|
||||
if (ignore) {
|
||||
if (s.sa_handler == SIG_DFL) /* Ignore only if there isn't any custom handler */
|
||||
new_handler = SIG_IGN;
|
||||
} else {
|
||||
if (s.sa_handler == SIG_IGN) /* Restore only if noone modified our SIG_IGN */
|
||||
new_handler = SIG_DFL;
|
||||
}
|
||||
|
||||
if (new_handler) {
|
||||
s.sa_handler = new_handler;
|
||||
s.sa_flags = 0;
|
||||
sigaction(signum, &s, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void uloop_setup_signals(bool add)
|
||||
{
|
||||
static struct sigaction old_sigint, old_sigchld, old_sigterm;
|
||||
|
||||
uloop_install_handler(SIGINT, uloop_handle_sigint, &old_sigint, add);
|
||||
uloop_install_handler(SIGTERM, uloop_handle_sigint, &old_sigterm, add);
|
||||
uloop_install_handler(SIGCHLD, uloop_sigchld, &old_sigchld, add);
|
||||
|
||||
uloop_ignore_signal(SIGPIPE, add);
|
||||
}
|
||||
|
||||
static int uloop_get_next_timeout(struct timeval *tv)
|
||||
@@ -654,11 +680,13 @@ void uloop_run(void)
|
||||
{
|
||||
uloop_gettime(&tv);
|
||||
uloop_process_timeouts(&tv);
|
||||
if (uloop_cancelled)
|
||||
break;
|
||||
|
||||
if (do_sigchld)
|
||||
uloop_handle_processes();
|
||||
|
||||
if (uloop_cancelled)
|
||||
break;
|
||||
|
||||
uloop_gettime(&tv);
|
||||
uloop_run_events(uloop_get_next_timeout(&tv));
|
||||
}
|
||||
|
||||
@@ -20,14 +20,18 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <netdb.h>
|
||||
#include <poll.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include "usock.h"
|
||||
#include "utils.h"
|
||||
|
||||
static void usock_set_flags(int sock, unsigned int type)
|
||||
{
|
||||
@@ -38,7 +42,7 @@ static void usock_set_flags(int sock, unsigned int type)
|
||||
fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
|
||||
}
|
||||
|
||||
static int usock_connect(struct sockaddr *sa, int sa_len, int family, int socktype, bool server)
|
||||
static int usock_connect(int type, struct sockaddr *sa, int sa_len, int family, int socktype, bool server)
|
||||
{
|
||||
int sock;
|
||||
|
||||
@@ -46,6 +50,8 @@ static int usock_connect(struct sockaddr *sa, int sa_len, int family, int sockty
|
||||
if (sock < 0)
|
||||
return -1;
|
||||
|
||||
usock_set_flags(sock, type);
|
||||
|
||||
if (server) {
|
||||
const int one = 1;
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
|
||||
@@ -62,9 +68,11 @@ static int usock_connect(struct sockaddr *sa, int sa_len, int family, int sockty
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int usock_unix(const char *host, int socktype, bool server)
|
||||
static int usock_unix(int type, const char *host)
|
||||
{
|
||||
struct sockaddr_un sun = {.sun_family = AF_UNIX};
|
||||
bool server = !!(type & USOCK_SERVER);
|
||||
int socktype = ((type & 0xff) == USOCK_TCP) ? SOCK_STREAM : SOCK_DGRAM;
|
||||
|
||||
if (strlen(host) >= sizeof(sun.sun_path)) {
|
||||
errno = EINVAL;
|
||||
@@ -72,11 +80,65 @@ static int usock_unix(const char *host, int socktype, bool server)
|
||||
}
|
||||
strcpy(sun.sun_path, host);
|
||||
|
||||
return usock_connect((struct sockaddr*)&sun, sizeof(sun), AF_UNIX, socktype, server);
|
||||
return usock_connect(type, (struct sockaddr*)&sun, sizeof(sun), AF_UNIX, socktype, server);
|
||||
}
|
||||
|
||||
static int usock_inet(int type, const char *host, const char *service, int socktype, bool server)
|
||||
static int
|
||||
usock_inet_notimeout(int type, struct addrinfo *result, void *addr)
|
||||
{
|
||||
struct addrinfo *rp;
|
||||
int socktype = ((type & 0xff) == USOCK_TCP) ? SOCK_STREAM : SOCK_DGRAM;
|
||||
bool server = !!(type & USOCK_SERVER);
|
||||
int sock;
|
||||
|
||||
for (rp = result; rp != NULL; rp = rp->ai_next) {
|
||||
sock = usock_connect(type, rp->ai_addr, rp->ai_addrlen, rp->ai_family, socktype, server);
|
||||
if (sock >= 0) {
|
||||
if (addr)
|
||||
memcpy(addr, rp->ai_addr, rp->ai_addrlen);
|
||||
return sock;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int poll_restart(struct pollfd *fds, int nfds, int timeout)
|
||||
{
|
||||
struct timespec ts, cur;
|
||||
int msec = timeout % 1000;
|
||||
int ret;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
|
||||
ts.tv_nsec += msec * 1000000;
|
||||
if (ts.tv_nsec > 1000000000) {
|
||||
ts.tv_sec++;
|
||||
ts.tv_nsec -= 1000000000;
|
||||
}
|
||||
ts.tv_sec += timeout / 1000;
|
||||
|
||||
while (1) {
|
||||
ret = poll(fds, nfds, timeout);
|
||||
if (ret == EAGAIN)
|
||||
continue;
|
||||
|
||||
if (ret != EINTR)
|
||||
return ret;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur);
|
||||
timeout = (ts.tv_sec - cur.tv_sec) * 1000;
|
||||
timeout += (ts.tv_nsec - cur.tv_nsec) / 1000000;
|
||||
if (timeout <= 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int usock_inet_timeout(int type, const char *host, const char *service,
|
||||
void *addr, int timeout)
|
||||
{
|
||||
int socktype = ((type & 0xff) == USOCK_TCP) ? SOCK_STREAM : SOCK_DGRAM;
|
||||
bool server = !!(type & USOCK_SERVER);
|
||||
struct addrinfo *result, *rp;
|
||||
struct addrinfo hints = {
|
||||
.ai_family = (type & USOCK_IPV6ONLY) ? AF_INET6 :
|
||||
@@ -86,34 +148,146 @@ static int usock_inet(int type, const char *host, const char *service, int sockt
|
||||
| ((type & USOCK_SERVER) ? AI_PASSIVE : 0)
|
||||
| ((type & USOCK_NUMERIC) ? AI_NUMERICHOST : 0),
|
||||
};
|
||||
struct addrinfo *rp_v6 = NULL;
|
||||
struct addrinfo *rp_v4 = NULL;
|
||||
struct pollfd pfds[2] = {
|
||||
{ .fd = -1, .events = POLLOUT },
|
||||
{ .fd = -1, .events = POLLOUT },
|
||||
};
|
||||
int sock = -1;
|
||||
int i;
|
||||
|
||||
if (getaddrinfo(host, service, &hints, &result))
|
||||
return -1;
|
||||
|
||||
for (rp = result; rp != NULL; rp = rp->ai_next) {
|
||||
sock = usock_connect(rp->ai_addr, rp->ai_addrlen, rp->ai_family, socktype, server);
|
||||
if (sock >= 0)
|
||||
break;
|
||||
if (timeout <= 0 || server) {
|
||||
sock = usock_inet_notimeout(type, result, addr);
|
||||
goto free_addrinfo;
|
||||
}
|
||||
|
||||
for (rp = result; rp != NULL; rp = rp->ai_next) {
|
||||
if (rp->ai_family == AF_INET6 && !rp_v6)
|
||||
rp_v6 = rp;
|
||||
if (rp->ai_family == AF_INET && !rp_v4)
|
||||
rp_v4 = rp;
|
||||
}
|
||||
|
||||
if (!rp_v6 && !rp_v4)
|
||||
goto out;
|
||||
|
||||
if (rp_v6) {
|
||||
rp = rp_v6;
|
||||
pfds[0].fd = usock_connect(type | USOCK_NONBLOCK, rp->ai_addr,
|
||||
rp->ai_addrlen, rp->ai_family,
|
||||
socktype, server);
|
||||
if (pfds[0].fd < 0) {
|
||||
rp_v6 = NULL;
|
||||
goto try_v4;
|
||||
}
|
||||
|
||||
if (timeout > 300) {
|
||||
if (poll_restart(pfds, 1, 300) == 1) {
|
||||
rp = rp_v6;
|
||||
sock = pfds[0].fd;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
timeout -= 300;
|
||||
}
|
||||
|
||||
try_v4:
|
||||
if (rp_v4) {
|
||||
rp = rp_v4;
|
||||
pfds[1].fd = usock_connect(type | USOCK_NONBLOCK, rp->ai_addr,
|
||||
rp->ai_addrlen, rp->ai_family,
|
||||
socktype, server);
|
||||
if (pfds[1].fd < 0) {
|
||||
rp_v4 = NULL;
|
||||
if (!rp_v6)
|
||||
goto out;
|
||||
goto wait;
|
||||
}
|
||||
}
|
||||
|
||||
wait:
|
||||
poll_restart(pfds + !rp_v6, !!rp_v6 + !!rp_v4, timeout);
|
||||
if (pfds[0].revents & POLLOUT) {
|
||||
rp = rp_v6;
|
||||
sock = pfds[0].fd;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pfds[1].revents & POLLOUT) {
|
||||
rp = rp_v4;
|
||||
sock = pfds[1].fd;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
for (i = 0; i < 2; i++) {
|
||||
int fd = pfds[i].fd;
|
||||
if (fd >= 0 && fd != sock)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (!(type & USOCK_NONBLOCK))
|
||||
fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) & ~O_NONBLOCK);
|
||||
|
||||
if (addr && sock >= 0)
|
||||
memcpy(addr, rp->ai_addr, rp->ai_addrlen);
|
||||
free_addrinfo:
|
||||
freeaddrinfo(result);
|
||||
return sock;
|
||||
}
|
||||
|
||||
const char *usock_port(int port)
|
||||
{
|
||||
static char buffer[sizeof("65535\0")];
|
||||
|
||||
if (port < 0 || port > 65535)
|
||||
return NULL;
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "%u", port);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int usock(int type, const char *host, const char *service) {
|
||||
int socktype = ((type & 0xff) == USOCK_TCP) ? SOCK_STREAM : SOCK_DGRAM;
|
||||
bool server = !!(type & USOCK_SERVER);
|
||||
int sock;
|
||||
|
||||
if (type & USOCK_UNIX)
|
||||
sock = usock_unix(host, socktype, server);
|
||||
sock = usock_unix(type, host);
|
||||
else
|
||||
sock = usock_inet(type, host, service, socktype, server);
|
||||
sock = usock_inet(type, host, service, NULL);
|
||||
|
||||
if (sock < 0)
|
||||
return -1;
|
||||
|
||||
usock_set_flags(sock, type);
|
||||
return sock;
|
||||
}
|
||||
|
||||
int usock_wait_ready(int fd, int msecs) {
|
||||
struct pollfd fds[1];
|
||||
int res;
|
||||
|
||||
fds[0].fd = fd;
|
||||
fds[0].events = POLLOUT;
|
||||
|
||||
res = poll(fds, 1, msecs);
|
||||
if (res < 0) {
|
||||
return errno;
|
||||
} else if (res == 0) {
|
||||
return -ETIMEDOUT;
|
||||
} else {
|
||||
int err = 0;
|
||||
socklen_t optlen = sizeof(err);
|
||||
|
||||
res = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &optlen);
|
||||
if (res)
|
||||
return errno;
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,25 @@
|
||||
#define USOCK_IPV4ONLY 0x4000
|
||||
#define USOCK_UNIX 0x8000
|
||||
|
||||
const char *usock_port(int port);
|
||||
int usock(int type, const char *host, const char *service);
|
||||
int usock_inet_timeout(int type, const char *host, const char *service,
|
||||
void *addr, int timeout);
|
||||
static inline int
|
||||
usock_inet(int type, const char *host, const char *service, void *addr)
|
||||
{
|
||||
return usock_inet_timeout(type, host, service, addr, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for a socket to become ready.
|
||||
*
|
||||
* This may be useful for users of USOCK_NONBLOCK to wait (with a timeout)
|
||||
* for a socket.
|
||||
*
|
||||
* @param fd file descriptor of socket
|
||||
* @param msecs timeout in microseconds
|
||||
*/
|
||||
int usock_wait_ready(int fd, int msecs);
|
||||
|
||||
#endif /* USOCK_H_ */
|
||||
|
||||
@@ -25,7 +25,7 @@ static void ustream_fd_set_uloop(struct ustream *s, bool write)
|
||||
{
|
||||
struct ustream_fd *sf = container_of(s, struct ustream_fd, stream);
|
||||
struct ustream_buf *buf;
|
||||
unsigned int flags = ULOOP_EDGE_TRIGGER;
|
||||
unsigned int flags = ULOOP_EDGE_TRIGGER | ULOOP_ERROR_CB;
|
||||
|
||||
if (!s->read_blocked && !s->eof)
|
||||
flags |= ULOOP_READ;
|
||||
@@ -50,6 +50,9 @@ static void ustream_fd_read_pending(struct ustream_fd *sf, bool *more)
|
||||
char *buf;
|
||||
|
||||
do {
|
||||
if (s->read_blocked)
|
||||
break;
|
||||
|
||||
buf = ustream_reserve(s, 1, &buflen);
|
||||
if (!buf)
|
||||
break;
|
||||
@@ -59,7 +62,7 @@ static void ustream_fd_read_pending(struct ustream_fd *sf, bool *more)
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (errno == EAGAIN)
|
||||
if (errno == EAGAIN || errno == ENOTCONN)
|
||||
return;
|
||||
|
||||
len = 0;
|
||||
@@ -93,7 +96,7 @@ static int ustream_fd_write(struct ustream *s, const char *buf, int buflen, bool
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOTCONN)
|
||||
break;
|
||||
|
||||
return -1;
|
||||
@@ -119,10 +122,17 @@ static bool __ustream_fd_poll(struct ustream_fd *sf, unsigned int events)
|
||||
ustream_fd_read_pending(sf, &more);
|
||||
|
||||
if (events & ULOOP_WRITE) {
|
||||
if (!ustream_write_pending(s))
|
||||
bool no_more = ustream_write_pending(s);
|
||||
if (no_more)
|
||||
ustream_fd_set_uloop(s, false);
|
||||
}
|
||||
|
||||
if (sf->fd.error && !s->write_error) {
|
||||
ustream_state_change(s);
|
||||
s->write_error = true;
|
||||
ustream_fd_set_uloop(s, false);
|
||||
}
|
||||
|
||||
return more;
|
||||
}
|
||||
|
||||
|
||||
@@ -145,21 +145,26 @@ static bool ustream_should_move(struct ustream_buf_list *l, struct ustream_buf *
|
||||
int maxlen;
|
||||
int offset;
|
||||
|
||||
/* nothing to squeeze */
|
||||
if (buf->data == buf->head)
|
||||
return false;
|
||||
|
||||
maxlen = buf->end - buf->head;
|
||||
offset = buf->data - buf->head;
|
||||
|
||||
/* less than half is available */
|
||||
if (offset > maxlen / 2)
|
||||
return true;
|
||||
|
||||
/* less than 32 bytes data but takes more than 1/4 space */
|
||||
if (buf->tail - buf->data < 32 && offset > maxlen / 4)
|
||||
return true;
|
||||
|
||||
/* more buf is already in list or can be allocated */
|
||||
if (buf != l->tail || ustream_can_alloc(l))
|
||||
return false;
|
||||
|
||||
/* no need to move if len is available at the tail */
|
||||
return (buf->end - buf->tail < len);
|
||||
}
|
||||
|
||||
@@ -255,13 +260,14 @@ static bool ustream_prepare_buf(struct ustream *s, struct ustream_buf_list *l, i
|
||||
if (l == &s->r)
|
||||
ustream_fixup_string(s, buf);
|
||||
}
|
||||
/* some chunks available at the tail */
|
||||
if (buf->tail != buf->end)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (buf && buf->next) {
|
||||
l->data_tail = buf->next;
|
||||
return true;
|
||||
/* next buf available */
|
||||
if (buf->next) {
|
||||
l->data_tail = buf->next;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ustream_can_alloc(l))
|
||||
@@ -333,6 +339,26 @@ char *ustream_get_read_buf(struct ustream *s, int *buflen)
|
||||
return data;
|
||||
}
|
||||
|
||||
int ustream_read(struct ustream *s, char *buf, int buflen)
|
||||
{
|
||||
char *chunk;
|
||||
int chunk_len;
|
||||
int len = 0;
|
||||
|
||||
do {
|
||||
chunk = ustream_get_read_buf(s, &chunk_len);
|
||||
if (!chunk)
|
||||
break;
|
||||
if (chunk_len > buflen - len)
|
||||
chunk_len = buflen - len;
|
||||
memcpy(buf + len, chunk, chunk_len);
|
||||
ustream_consume(s, chunk_len);
|
||||
len += chunk_len;
|
||||
} while (len < buflen);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static void ustream_write_error(struct ustream *s)
|
||||
{
|
||||
if (!s->write_error)
|
||||
|
||||
@@ -143,6 +143,11 @@ void ustream_free(struct ustream *s);
|
||||
/* ustream_consume: remove data from the head of the read buffer */
|
||||
void ustream_consume(struct ustream *s, int len);
|
||||
|
||||
/*
|
||||
* ustream_read: read and consume data in read buffer into caller-specified
|
||||
* area. Return length of data read.
|
||||
*/
|
||||
int ustream_read(struct ustream *s, char *buf, int buflen);
|
||||
/* ustream_write: add data to the write buffer */
|
||||
int ustream_write(struct ustream *s, const char *buf, int len, bool more);
|
||||
int ustream_printf(struct ustream *s, const char *format, ...);
|
||||
|
||||
@@ -54,41 +54,50 @@ void *__calloc_a(size_t len, ...)
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <mach/mach_time.h>
|
||||
#include <mach/mach_host.h> /* host_get_clock_service() */
|
||||
#include <mach/mach_port.h> /* mach_port_deallocate() */
|
||||
#include <mach/mach_init.h> /* mach_host_self(), mach_task_self() */
|
||||
#include <mach/clock.h> /* clock_get_time() */
|
||||
|
||||
static void clock_gettime_realtime(struct timespec *tv)
|
||||
static clock_serv_t clock_realtime;
|
||||
static clock_serv_t clock_monotonic;
|
||||
|
||||
static void __constructor clock_name_init(void)
|
||||
{
|
||||
struct timeval _tv;
|
||||
mach_port_t host_self = mach_host_self();
|
||||
|
||||
gettimeofday(&_tv, NULL);
|
||||
tv->tv_sec = _tv.tv_sec;
|
||||
tv->tv_nsec = _tv.tv_usec * 1000;
|
||||
host_get_clock_service(host_self, CLOCK_REALTIME, &clock_realtime);
|
||||
host_get_clock_service(host_self, CLOCK_MONOTONIC, &clock_monotonic);
|
||||
}
|
||||
|
||||
static void clock_gettime_monotonic(struct timespec *tv)
|
||||
static void __destructor clock_name_dealloc(void)
|
||||
{
|
||||
mach_timebase_info_data_t info;
|
||||
float sec;
|
||||
uint64_t val;
|
||||
mach_port_t self = mach_task_self();
|
||||
|
||||
mach_timebase_info(&info);
|
||||
|
||||
val = mach_absolute_time();
|
||||
tv->tv_nsec = (val * info.numer / info.denom) % 1000000000;
|
||||
|
||||
sec = val;
|
||||
sec *= info.numer;
|
||||
sec /= info.denom;
|
||||
sec /= 1000000000;
|
||||
tv->tv_sec = sec;
|
||||
mach_port_deallocate(self, clock_realtime);
|
||||
mach_port_deallocate(self, clock_monotonic);
|
||||
}
|
||||
|
||||
void clock_gettime(int type, struct timespec *tv)
|
||||
int clock_gettime(int type, struct timespec *tv)
|
||||
{
|
||||
if (type == CLOCK_REALTIME)
|
||||
return clock_gettime_realtime(tv);
|
||||
else
|
||||
return clock_gettime_monotonic(tv);
|
||||
int retval = -1;
|
||||
mach_timespec_t mts;
|
||||
|
||||
switch (type) {
|
||||
case CLOCK_REALTIME:
|
||||
retval = clock_get_time(clock_realtime, &mts);
|
||||
break;
|
||||
case CLOCK_MONOTONIC:
|
||||
retval = clock_get_time(clock_monotonic, &mts);
|
||||
break;
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
|
||||
tv->tv_sec = mts.tv_sec;
|
||||
tv->tv_nsec = mts.tv_nsec;
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -58,10 +58,11 @@ extern int __BUILD_BUG_ON_CONDITION_FAILED;
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
#define CLOCK_REALTIME 0
|
||||
#define CLOCK_MONOTONIC 1
|
||||
#include <mach/clock_types.h>
|
||||
#define CLOCK_REALTIME CALENDAR_CLOCK
|
||||
#define CLOCK_MONOTONIC SYSTEM_CLOCK
|
||||
|
||||
void clock_gettime(int type, struct timespec *tv);
|
||||
int clock_gettime(int type, struct timespec *tv);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -159,6 +160,10 @@ static inline uint16_t __u_bswap16(uint16_t val)
|
||||
#define __constructor __attribute__((constructor))
|
||||
#endif
|
||||
|
||||
#ifndef __destructor
|
||||
#define __destructor __attribute__((destructor))
|
||||
#endif
|
||||
|
||||
#ifndef __hidden
|
||||
#define __hidden __attribute__((visibility("hidden")))
|
||||
#endif
|
||||
@@ -179,4 +184,12 @@ static inline bool bitfield_test(unsigned long *bits, int bit)
|
||||
return !!(bits[bit / BITS_PER_LONG] & (1UL << (bit % BITS_PER_LONG)));
|
||||
}
|
||||
|
||||
int b64_encode(const void *src, size_t src_len,
|
||||
void *dest, size_t dest_len);
|
||||
|
||||
int b64_decode(const void *src, void *dest, size_t dest_len);
|
||||
|
||||
#define B64_ENCODE_LEN(_len) ((((_len) + 2) / 3) * 4 + 1)
|
||||
#define B64_DECODE_LEN(_len) (((_len) / 4) * 3 + 1)
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user