aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am14
-rw-r--r--src/Makefile.in70
-rw-r--r--src/cjson.c786
-rw-r--r--src/cjson.h184
-rw-r--r--src/dscp.c5
-rw-r--r--[-rwxr-xr-x]src/iperf.h0
-rw-r--r--src/iperf3.16
-rw-r--r--[-rwxr-xr-x]src/iperf_api.c107
-rw-r--r--[-rwxr-xr-x]src/iperf_api.h9
-rw-r--r--src/iperf_auth.c79
-rw-r--r--src/iperf_auth.h1
-rw-r--r--src/iperf_error.c6
-rw-r--r--src/iperf_locale.c6
-rw-r--r--src/iperf_locale.h6
-rw-r--r--src/iperf_sctp.c58
-rw-r--r--src/iperf_tcp.c1
-rw-r--r--src/iperf_udp.c21
-rw-r--r--src/main.c3
-rw-r--r--src/net.c1
-rw-r--r--src/private.pem27
-rw-r--r--src/public.pem9
-rw-r--r--src/t_api.c14
-rw-r--r--src/t_auth.c125
-rw-r--r--src/tcp_info.c4
-rw-r--r--src/timer.h2
25 files changed, 1219 insertions, 325 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 5be8562..11d3e17 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,9 +1,9 @@
lib_LTLIBRARIES = libiperf.la # Build and install an iperf library
bin_PROGRAMS = iperf3 # Build and install an iperf binary
if ENABLE_PROFILING
-noinst_PROGRAMS = t_timer t_units t_uuid t_api iperf3_profile # Build, but don't install the test programs and a profiled version of iperf3
+noinst_PROGRAMS = t_timer t_units t_uuid t_api t_auth iperf3_profile # Build, but don't install the test programs and a profiled version of iperf3
else
-noinst_PROGRAMS = t_timer t_units t_uuid t_api # Build, but don't install the test programs
+noinst_PROGRAMS = t_timer t_units t_uuid t_api t_auth # Build, but don't install the test programs
endif
include_HEADERS = iperf_api.h # Defines the headers that get installed with the program
@@ -52,7 +52,7 @@ iperf3_LDADD = libiperf.la
iperf3_LDFLAGS = -g
if ENABLE_PROFILING
-# If the iperf-profiled-binary is enabled (and this condition is true by default)
+# If the iperf-profiled-binary is enabled
# Specify the sources and various flags for the profiled iperf binary. This
# binary recompiles all the source files to make sure they are all profiled.
iperf3_profile_SOURCES = main.c \
@@ -84,6 +84,11 @@ t_api_CFLAGS = -g
t_api_LDFLAGS =
t_api_LDADD = libiperf.la
+t_auth_SOURCES = t_auth.c
+t_auth_CFLAGS = -g
+t_auth_LDFLAGS =
+t_auth_LDADD = libiperf.la
+
# Specify which tests to run during a "make check"
@@ -91,6 +96,7 @@ TESTS = \
t_timer \
t_units \
t_uuid \
- t_api
+ t_api \
+ t_auth
dist_man_MANS = iperf3.1 libiperf.3
diff --git a/src/Makefile.in b/src/Makefile.in
index 619cd45..271ef6c 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# Makefile.in generated by automake 1.16.2 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -93,15 +93,17 @@ host_triplet = @host@
bin_PROGRAMS = iperf3$(EXEEXT)
@ENABLE_PROFILING_FALSE@noinst_PROGRAMS = t_timer$(EXEEXT) \
@ENABLE_PROFILING_FALSE@ t_units$(EXEEXT) t_uuid$(EXEEXT) \
-@ENABLE_PROFILING_FALSE@ t_api$(EXEEXT)
+@ENABLE_PROFILING_FALSE@ t_api$(EXEEXT) t_auth$(EXEEXT)
@ENABLE_PROFILING_TRUE@noinst_PROGRAMS = t_timer$(EXEEXT) \
@ENABLE_PROFILING_TRUE@ t_units$(EXEEXT) t_uuid$(EXEEXT) \
-@ENABLE_PROFILING_TRUE@ t_api$(EXEEXT) iperf3_profile$(EXEEXT)
+@ENABLE_PROFILING_TRUE@ t_api$(EXEEXT) t_auth$(EXEEXT) \
+@ENABLE_PROFILING_TRUE@ iperf3_profile$(EXEEXT)
TESTS = t_timer$(EXEEXT) t_units$(EXEEXT) t_uuid$(EXEEXT) \
- t_api$(EXEEXT)
+ t_api$(EXEEXT) t_auth$(EXEEXT)
subdir = src
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/config/ax_check_openssl.m4 \
+ $(top_srcdir)/config/iperf_config_static_bin.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
@@ -198,6 +200,12 @@ t_api_DEPENDENCIES = libiperf.la
t_api_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(t_api_CFLAGS) $(CFLAGS) \
$(t_api_LDFLAGS) $(LDFLAGS) -o $@
+am_t_auth_OBJECTS = t_auth-t_auth.$(OBJEXT)
+t_auth_OBJECTS = $(am_t_auth_OBJECTS)
+t_auth_DEPENDENCIES = libiperf.la
+t_auth_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(t_auth_CFLAGS) $(CFLAGS) \
+ $(t_auth_LDFLAGS) $(LDFLAGS) -o $@
am_t_timer_OBJECTS = t_timer-t_timer.$(OBJEXT)
t_timer_OBJECTS = $(am_t_timer_OBJECTS)
t_timer_DEPENDENCIES = libiperf.la
@@ -256,9 +264,10 @@ am__depfiles_remade = ./$(DEPDIR)/cjson.Plo ./$(DEPDIR)/dscp.Plo \
./$(DEPDIR)/iperf_tcp.Plo ./$(DEPDIR)/iperf_time.Plo \
./$(DEPDIR)/iperf_udp.Plo ./$(DEPDIR)/iperf_util.Plo \
./$(DEPDIR)/net.Plo ./$(DEPDIR)/t_api-t_api.Po \
- ./$(DEPDIR)/t_timer-t_timer.Po ./$(DEPDIR)/t_units-t_units.Po \
- ./$(DEPDIR)/t_uuid-t_uuid.Po ./$(DEPDIR)/tcp_info.Plo \
- ./$(DEPDIR)/timer.Plo ./$(DEPDIR)/units.Plo
+ ./$(DEPDIR)/t_auth-t_auth.Po ./$(DEPDIR)/t_timer-t_timer.Po \
+ ./$(DEPDIR)/t_units-t_units.Po ./$(DEPDIR)/t_uuid-t_uuid.Po \
+ ./$(DEPDIR)/tcp_info.Plo ./$(DEPDIR)/timer.Plo \
+ ./$(DEPDIR)/units.Plo
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@@ -279,11 +288,12 @@ am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(libiperf_la_SOURCES) $(iperf3_SOURCES) \
- $(iperf3_profile_SOURCES) $(t_api_SOURCES) $(t_timer_SOURCES) \
- $(t_units_SOURCES) $(t_uuid_SOURCES)
+ $(iperf3_profile_SOURCES) $(t_api_SOURCES) $(t_auth_SOURCES) \
+ $(t_timer_SOURCES) $(t_units_SOURCES) $(t_uuid_SOURCES)
DIST_SOURCES = $(libiperf_la_SOURCES) $(iperf3_SOURCES) \
$(am__iperf3_profile_SOURCES_DIST) $(t_api_SOURCES) \
- $(t_timer_SOURCES) $(t_units_SOURCES) $(t_uuid_SOURCES)
+ $(t_auth_SOURCES) $(t_timer_SOURCES) $(t_units_SOURCES) \
+ $(t_uuid_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
@@ -294,8 +304,8 @@ man3dir = $(mandir)/man3
NROFF = nroff
MANS = $(dist_man_MANS)
HEADERS = $(include_HEADERS)
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
- $(LISP)iperf_config.h.in
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) \
+ iperf_config.h.in
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
@@ -664,7 +674,7 @@ iperf3_CFLAGS = -g
iperf3_LDADD = libiperf.la
iperf3_LDFLAGS = -g
-# If the iperf-profiled-binary is enabled (and this condition is true by default)
+# If the iperf-profiled-binary is enabled
# Specify the sources and various flags for the profiled iperf binary. This
# binary recompiles all the source files to make sure they are all profiled.
@ENABLE_PROFILING_TRUE@iperf3_profile_SOURCES = main.c \
@@ -691,6 +701,10 @@ t_api_SOURCES = t_api.c
t_api_CFLAGS = -g
t_api_LDFLAGS =
t_api_LDADD = libiperf.la
+t_auth_SOURCES = t_auth.c
+t_auth_CFLAGS = -g
+t_auth_LDFLAGS =
+t_auth_LDADD = libiperf.la
dist_man_MANS = iperf3.1 libiperf.3
all: iperf_config.h
$(MAKE) $(AM_MAKEFLAGS) all-am
@@ -852,6 +866,10 @@ t_api$(EXEEXT): $(t_api_OBJECTS) $(t_api_DEPENDENCIES) $(EXTRA_t_api_DEPENDENCIE
@rm -f t_api$(EXEEXT)
$(AM_V_CCLD)$(t_api_LINK) $(t_api_OBJECTS) $(t_api_LDADD) $(LIBS)
+t_auth$(EXEEXT): $(t_auth_OBJECTS) $(t_auth_DEPENDENCIES) $(EXTRA_t_auth_DEPENDENCIES)
+ @rm -f t_auth$(EXEEXT)
+ $(AM_V_CCLD)$(t_auth_LINK) $(t_auth_OBJECTS) $(t_auth_LDADD) $(LIBS)
+
t_timer$(EXEEXT): $(t_timer_OBJECTS) $(t_timer_DEPENDENCIES) $(EXTRA_t_timer_DEPENDENCIES)
@rm -f t_timer$(EXEEXT)
$(AM_V_CCLD)$(t_timer_LINK) $(t_timer_OBJECTS) $(t_timer_LDADD) $(LIBS)
@@ -904,6 +922,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf_util.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t_api-t_api.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t_auth-t_auth.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t_timer-t_timer.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t_units-t_units.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t_uuid-t_uuid.Po@am__quote@ # am--include-marker
@@ -1218,6 +1237,20 @@ t_api-t_api.obj: t_api.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(t_api_CFLAGS) $(CFLAGS) -c -o t_api-t_api.obj `if test -f 't_api.c'; then $(CYGPATH_W) 't_api.c'; else $(CYGPATH_W) '$(srcdir)/t_api.c'; fi`
+t_auth-t_auth.o: t_auth.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(t_auth_CFLAGS) $(CFLAGS) -MT t_auth-t_auth.o -MD -MP -MF $(DEPDIR)/t_auth-t_auth.Tpo -c -o t_auth-t_auth.o `test -f 't_auth.c' || echo '$(srcdir)/'`t_auth.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/t_auth-t_auth.Tpo $(DEPDIR)/t_auth-t_auth.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='t_auth.c' object='t_auth-t_auth.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(t_auth_CFLAGS) $(CFLAGS) -c -o t_auth-t_auth.o `test -f 't_auth.c' || echo '$(srcdir)/'`t_auth.c
+
+t_auth-t_auth.obj: t_auth.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(t_auth_CFLAGS) $(CFLAGS) -MT t_auth-t_auth.obj -MD -MP -MF $(DEPDIR)/t_auth-t_auth.Tpo -c -o t_auth-t_auth.obj `if test -f 't_auth.c'; then $(CYGPATH_W) 't_auth.c'; else $(CYGPATH_W) '$(srcdir)/t_auth.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/t_auth-t_auth.Tpo $(DEPDIR)/t_auth-t_auth.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='t_auth.c' object='t_auth-t_auth.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(t_auth_CFLAGS) $(CFLAGS) -c -o t_auth-t_auth.obj `if test -f 't_auth.c'; then $(CYGPATH_W) 't_auth.c'; else $(CYGPATH_W) '$(srcdir)/t_auth.c'; fi`
+
t_timer-t_timer.o: t_timer.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(t_timer_CFLAGS) $(CFLAGS) -MT t_timer-t_timer.o -MD -MP -MF $(DEPDIR)/t_timer-t_timer.Tpo -c -o t_timer-t_timer.o `test -f 't_timer.c' || echo '$(srcdir)/'`t_timer.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/t_timer-t_timer.Tpo $(DEPDIR)/t_timer-t_timer.Po
@@ -1594,6 +1627,13 @@ t_api.log: t_api$(EXEEXT)
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
+t_auth.log: t_auth$(EXEEXT)
+ @p='t_auth$(EXEEXT)'; \
+ b='t_auth'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
.test.log:
@p='$<'; \
$(am__set_b); \
@@ -1726,6 +1766,7 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/iperf_util.Plo
-rm -f ./$(DEPDIR)/net.Plo
-rm -f ./$(DEPDIR)/t_api-t_api.Po
+ -rm -f ./$(DEPDIR)/t_auth-t_auth.Po
-rm -f ./$(DEPDIR)/t_timer-t_timer.Po
-rm -f ./$(DEPDIR)/t_units-t_units.Po
-rm -f ./$(DEPDIR)/t_uuid-t_uuid.Po
@@ -1811,6 +1852,7 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/iperf_util.Plo
-rm -f ./$(DEPDIR)/net.Plo
-rm -f ./$(DEPDIR)/t_api-t_api.Po
+ -rm -f ./$(DEPDIR)/t_auth-t_auth.Po
-rm -f ./$(DEPDIR)/t_timer-t_timer.Po
-rm -f ./$(DEPDIR)/t_units-t_units.Po
-rm -f ./$(DEPDIR)/t_uuid-t_uuid.Po
diff --git a/src/cjson.c b/src/cjson.c
index a31874d..bf0b8b4 100644
--- a/src/cjson.c
+++ b/src/cjson.c
@@ -23,23 +23,39 @@
/* cJSON */
/* JSON parser in C. */
+/* disable warnings about old C89 functions in MSVC */
+#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
#ifdef __GNUC__
#pragma GCC visibility push(default)
#endif
+#if defined(_MSC_VER)
+#pragma warning (push)
+/* disable warning about single line comments in system headers */
+#pragma warning (disable : 4001)
+#endif
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
-#include <float.h>
#include <limits.h>
#include <ctype.h>
+#include <float.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include <sys/types.h>
+
+#ifdef ENABLE_LOCALES
#include <locale.h>
+#endif
+#if defined(_MSC_VER)
+#pragma warning (pop)
+#endif
#ifdef __GNUC__
#pragma GCC visibility pop
#endif
@@ -47,9 +63,28 @@
#include "cjson.h"
/* define our own boolean type */
+#ifdef true
+#undef true
+#endif
#define true ((cJSON_bool)1)
+
+#ifdef false
+#undef false
+#endif
#define false ((cJSON_bool)0)
+/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */
+#ifndef isinf
+#define isinf(d) (isnan((d - d)) && !isnan(d))
+#endif
+#ifndef isnan
+#define isnan(d) (d != d)
+#endif
+
+#ifndef NAN
+#define NAN 0.0/0.0
+#endif
+
typedef struct {
const unsigned char *json;
size_t position;
@@ -68,8 +103,28 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
return (const char*) (global_error.json + global_error.position);
}
+CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item)
+{
+ if (!cJSON_IsString(item))
+ {
+ return NULL;
+ }
+
+ return item->valuestring;
+}
+
+CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *item)
+{
+ if (!cJSON_IsNumber(item))
+ {
+ return NAN;
+ }
+
+ return item->valuedouble;
+}
+
/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
-#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 5) || (CJSON_VERSION_PATCH != 2)
+#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 13)
#error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
#endif
@@ -107,12 +162,35 @@ static int case_insensitive_strcmp(const unsigned char *string1, const unsigned
typedef struct internal_hooks
{
- void *(*allocate)(size_t size);
- void (*deallocate)(void *pointer);
- void *(*reallocate)(void *pointer, size_t size);
+ void *(CJSON_CDECL *allocate)(size_t size);
+ void (CJSON_CDECL *deallocate)(void *pointer);
+ void *(CJSON_CDECL *reallocate)(void *pointer, size_t size);
} internal_hooks;
-static internal_hooks global_hooks = { malloc, free, realloc };
+#if defined(_MSC_VER)
+/* work around MSVC error C2322: '...' address of dllimport '...' is not static */
+static void * CJSON_CDECL internal_malloc(size_t size)
+{
+ return malloc(size);
+}
+static void CJSON_CDECL internal_free(void *pointer)
+{
+ free(pointer);
+}
+static void * CJSON_CDECL internal_realloc(void *pointer, size_t size)
+{
+ return realloc(pointer, size);
+}
+#else
+#define internal_malloc malloc
+#define internal_free free
+#define internal_realloc realloc
+#endif
+
+/* strlen of character literals resolved at compile time */
+#define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))
+
+static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc };
static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks)
{
@@ -125,7 +203,8 @@ static unsigned char* cJSON_strdup(const unsigned char* string, const internal_h
}
length = strlen((const char*)string) + sizeof("");
- if (!(copy = (unsigned char*)hooks->allocate(length)))
+ copy = (unsigned char*)hooks->allocate(length);
+ if (copy == NULL)
{
return NULL;
}
@@ -204,8 +283,12 @@ CJSON_PUBLIC(void) cJSON_Delete(cJSON *item)
/* get the decimal point character of the current locale */
static unsigned char get_decimal_point(void)
{
+#ifdef ENABLE_LOCALES
struct lconv *lconv = localeconv();
return (unsigned char) lconv->decimal_point[0];
+#else
+ return '.';
+#endif
}
typedef struct
@@ -219,7 +302,6 @@ typedef struct
/* check if the given size is left to read in a given parse buffer (starting with 1) */
#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
-#define cannot_read(buffer, size) (!can_read(buffer, size))
/* check if the buffer can be accessed at the given index (starting with 0) */
#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
@@ -288,7 +370,7 @@ loop_end:
{
item->valueint = LLONG_MAX;
}
- else if (number <= LLONG_MIN)
+ else if (number <= (double)LLONG_MIN)
{
item->valueint = LLONG_MIN;
}
@@ -310,7 +392,7 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
{
object->valueint = LLONG_MAX;
}
- else if (number <= LLONG_MIN)
+ else if (number <= (double)LLONG_MIN)
{
object->valueint = LLONG_MIN;
}
@@ -322,6 +404,33 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
return object->valuedouble = number;
}
+CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
+{
+ char *copy = NULL;
+ /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */
+ if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference))
+ {
+ return NULL;
+ }
+ if (strlen(valuestring) <= strlen(object->valuestring))
+ {
+ strcpy(object->valuestring, valuestring);
+ return object->valuestring;
+ }
+ copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks);
+ if (copy == NULL)
+ {
+ return NULL;
+ }
+ if (object->valuestring != NULL)
+ {
+ cJSON_free(object->valuestring);
+ }
+ object->valuestring = copy;
+
+ return copy;
+}
+
typedef struct
{
unsigned char *buffer;
@@ -350,9 +459,9 @@ static unsigned char* ensure(printbuffer * const p, size_t needed)
return NULL;
}
- if (needed > LLONG_MAX)
+ if (needed > SIZE_MAX)
{
- /* sizes bigger than LLONG_MAX are currently not supported */
+ /* sizes bigger than SIZE_MAX are currently not supported */
return NULL;
}
@@ -367,12 +476,12 @@ static unsigned char* ensure(printbuffer * const p, size_t needed)
}
/* calculate new buffer size */
- if (needed > (LLONG_MAX / 2))
+ if (needed > (SIZE_MAX / 2))
{
- /* overflow of int, use LLONG_MAX if possible */
- if (needed <= LLONG_MAX)
+ /* overflow of int, use SIZE_MAX if possible */
+ if (needed <= SIZE_MAX)
{
- newsize = LLONG_MAX;
+ newsize = SIZE_MAX;
}
else
{
@@ -388,6 +497,14 @@ static unsigned char* ensure(printbuffer * const p, size_t needed)
{
/* reallocate with realloc if available */
newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize);
+ if (newbuffer == NULL)
+ {
+ p->hooks.deallocate(p->buffer);
+ p->length = 0;
+ p->buffer = NULL;
+
+ return NULL;
+ }
}
else
{
@@ -426,6 +543,13 @@ static void update_offset(printbuffer * const buffer)
buffer->offset += strlen((const char*)buffer_pointer);
}
+/* securely comparison of floating-point variables */
+static cJSON_bool compare_double(double a, double b)
+{
+ double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
+ return (fabs(a - b) <= maxVal * DBL_EPSILON);
+}
+
/* Render the number nicely from the given item into a string. */
static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
{
@@ -433,9 +557,9 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out
double d = item->valuedouble;
int length = 0;
size_t i = 0;
- unsigned char number_buffer[26]; /* temporary buffer to print the number into */
+ unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */
unsigned char decimal_point = get_decimal_point();
- double test;
+ double test = 0.0;
if (output_buffer == NULL)
{
@@ -443,7 +567,7 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out
}
/* This checks for NaN and Infinity */
- if ((d * 0) != 0)
+ if (isnan(d) || isinf(d))
{
length = sprintf((char*)number_buffer, "null");
}
@@ -453,21 +577,21 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out
length = sprintf((char*)number_buffer, "%1.15g", d);
/* Check whether the original double can be recovered */
- if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d))
+ if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d))
{
/* If not, print with 17 decimal places of precision */
length = sprintf((char*)number_buffer, "%1.17g", d);
}
}
- /* sprintf failed or buffer overrun occured */
+ /* sprintf failed or buffer overrun occurred */
if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
{
return false;
}
/* reserve appropriate space in the output */
- output_pointer = ensure(output_buffer, (size_t)length);
+ output_pointer = ensure(output_buffer, (size_t)length + sizeof(""));
if (output_pointer == NULL)
{
return false;
@@ -923,6 +1047,11 @@ static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
return NULL;
}
+ if (cannot_access_at_index(buffer, 0))
+ {
+ return buffer;
+ }
+
while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
{
buffer->offset++;
@@ -936,9 +1065,40 @@ static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
return buffer;
}
-/* Parse an object - create a new root, and populate. */
+/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
+static parse_buffer *skip_utf8_bom(parse_buffer * const buffer)
+{
+ if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0))
+ {
+ return NULL;
+ }
+
+ if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0))
+ {
+ buffer->offset += 3;
+ }
+
+ return buffer;
+}
+
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
{
+ size_t buffer_length;
+
+ if (NULL == value)
+ {
+ return NULL;
+ }
+
+ /* Adding null character size due to require_null_terminated. */
+ buffer_length = strlen(value) + sizeof("");
+
+ return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated);
+}
+
+/* Parse an object - create a new root, and populate. */
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated)
+{
parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
cJSON *item = NULL;
@@ -946,13 +1106,13 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return
global_error.json = NULL;
global_error.position = 0;
- if (value == NULL)
+ if (value == NULL || 0 == buffer_length)
{
goto fail;
}
buffer.content = (const unsigned char*)value;
- buffer.length = strlen((const char*)value) + sizeof("");
+ buffer.length = buffer_length;
buffer.offset = 0;
buffer.hooks = global_hooks;
@@ -962,7 +1122,7 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return
goto fail;
}
- if (!parse_value(item, buffer_skip_whitespace(&buffer)))
+ if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer))))
{
/* parse failure. ep is set. */
goto fail;
@@ -1009,10 +1169,8 @@ fail:
{
*return_parse_end = (const char*)local_error.json + local_error.position;
}
- else
- {
- global_error = local_error;
- }
+
+ global_error = local_error;
}
return NULL;
@@ -1024,17 +1182,24 @@ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
return cJSON_ParseWithOpts(value, 0, 0);
}
-#define cjson_min(a, b) ((a < b) ? a : b)
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length)
+{
+ return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0);
+}
+
+#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks)
{
+ static const size_t default_buffer_size = 256;
printbuffer buffer[1];
unsigned char *printed = NULL;
memset(buffer, 0, sizeof(buffer));
/* create buffer */
- buffer->buffer = (unsigned char*) hooks->allocate(256);
+ buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size);
+ buffer->length = default_buffer_size;
buffer->format = format;
buffer->hooks = *hooks;
if (buffer->buffer == NULL)
@@ -1052,11 +1217,11 @@ static unsigned char *print(const cJSON * const item, cJSON_bool format, const i
/* check if reallocate is available */
if (hooks->reallocate != NULL)
{
- printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->length);
- buffer->buffer = NULL;
+ printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1);
if (printed == NULL) {
goto fail;
}
+ buffer->buffer = NULL;
}
else /* otherwise copy the JSON over to a new buffer */
{
@@ -1122,26 +1287,27 @@ CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON
if (!print_value(item, &p))
{
+ global_hooks.deallocate(p.buffer);
return NULL;
}
return (char*)p.buffer;
}
-CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt)
+CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)
{
printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
- if (len < 0)
+ if ((length < 0) || (buffer == NULL))
{
return false;
}
- p.buffer = (unsigned char*)buf;
- p.length = (size_t)len;
+ p.buffer = (unsigned char*)buffer;
+ p.length = (size_t)length;
p.offset = 0;
p.noalloc = true;
- p.format = fmt;
+ p.format = format;
p.hooks = global_hooks;
return print_value(item, &p);
@@ -1199,7 +1365,6 @@ static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buf
return parse_object(item, input_buffer);
}
-
return false;
}
@@ -1250,10 +1415,6 @@ static cJSON_bool print_value(const cJSON * const item, printbuffer * const outp
size_t raw_length = 0;
if (item->valuestring == NULL)
{
- if (!output_buffer->noalloc)
- {
- output_buffer->hooks.deallocate(output_buffer->buffer);
- }
return false;
}
@@ -1499,7 +1660,7 @@ static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_bu
buffer_skip_whitespace(input_buffer);
if (!parse_string(current_item, input_buffer))
{
- goto fail; /* faile to parse name */
+ goto fail; /* failed to parse name */
}
buffer_skip_whitespace(input_buffer);
@@ -1619,7 +1780,7 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out
update_offset(output_buffer);
/* print comma if not last */
- length = (size_t) ((output_buffer->format ? 1 : 0) + (current_item->next ? 1 : 0));
+ length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0));
output_pointer = ensure(output_buffer, length + 1);
if (output_pointer == NULL)
{
@@ -1663,17 +1824,25 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out
/* Get Array size/item / object item. */
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array)
{
- cJSON *c = array->child;
- size_t i = 0;
- while(c)
+ cJSON *child = NULL;
+ size_t size = 0;
+
+ if (array == NULL)
+ {
+ return 0;
+ }
+
+ child = array->child;
+
+ while(child != NULL)
{
- i++;
- c = c->next;
+ size++;
+ child = child->next;
}
/* FIXME: Can overflow here. Cannot be fixed without breaking the API */
- return (int)i;
+ return (int)size;
}
static cJSON* get_array_item(const cJSON *array, size_t index)
@@ -1717,7 +1886,7 @@ static cJSON *get_object_item(const cJSON * const object, const char * const nam
current_element = object->child;
if (case_sensitive)
{
- while ((current_element != NULL) && (strcmp(name, current_element->string) != 0))
+ while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0))
{
current_element = current_element->next;
}
@@ -1730,6 +1899,10 @@ static cJSON *get_object_item(const cJSON * const object, const char * const nam
}
}
+ if ((current_element == NULL) || (current_element->string == NULL)) {
+ return NULL;
+ }
+
return current_element;
}
@@ -1758,88 +1931,263 @@ static void suffix_object(cJSON *prev, cJSON *item)
/* Utility for handling references. */
static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks)
{
- cJSON *ref = cJSON_New_Item(hooks);
- if (!ref)
+ cJSON *reference = NULL;
+ if (item == NULL)
+ {
+ return NULL;
+ }
+
+ reference = cJSON_New_Item(hooks);
+ if (reference == NULL)
{
return NULL;
}
- memcpy(ref, item, sizeof(cJSON));
- ref->string = NULL;
- ref->type |= cJSON_IsReference;
- ref->next = ref->prev = NULL;
- return ref;
+
+ memcpy(reference, item, sizeof(cJSON));
+ reference->string = NULL;
+ reference->type |= cJSON_IsReference;
+ reference->next = reference->prev = NULL;
+ return reference;
}
-/* Add item to array/object. */
-CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item)
+static cJSON_bool add_item_to_array(cJSON *array, cJSON *item)
{
cJSON *child = NULL;
- if ((item == NULL) || (array == NULL))
+ if ((item == NULL) || (array == NULL) || (array == item))
{
- return;
+ return false;
}
child = array->child;
-
+ /*
+ * To find the last item in array quickly, we use prev in array
+ */
if (child == NULL)
{
/* list is empty, start new one */
array->child = item;
+ item->prev = item;
+ item->next = NULL;
}
else
{
/* append to the end */
- while (child->next)
+ if (child->prev)
{
- child = child->next;
+ suffix_object(child->prev, item);
+ array->child->prev = item;
+ }
+ else
+ {
+ while (child->next)
+ {
+ child = child->next;
+ }
+ suffix_object(child, item);
+ array->child->prev = item;
}
- suffix_object(child, item);
}
+
+ return true;
}
-CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
+/* Add item to array/object. */
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item)
{
- /* call cJSON_AddItemToObjectCS for code reuse */
- cJSON_AddItemToObjectCS(object, (char*)cJSON_strdup((const unsigned char*)string, &global_hooks), item);
- /* remove cJSON_StringIsConst flag */
- item->type &= ~cJSON_StringIsConst;
+ return add_item_to_array(array, item);
}
-#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
+#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
#pragma GCC diagnostic push
#endif
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
+/* helper function to cast away const */
+static void* cast_away_const(const void* string)
+{
+ return (void*)string;
+}
+#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
+ #pragma GCC diagnostic pop
+#endif
+
+
+static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key)
+{
+ char *new_key = NULL;
+ int new_type = cJSON_Invalid;
+
+ if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item))
+ {
+ return false;
+ }
+
+ if (constant_key)
+ {
+ new_key = (char*)cast_away_const(string);
+ new_type = item->type | cJSON_StringIsConst;
+ }
+ else
+ {
+ new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks);
+ if (new_key == NULL)
+ {
+ return false;
+ }
+
+ new_type = item->type & ~cJSON_StringIsConst;
+ }
+
+ if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
+ {
+ hooks->deallocate(item->string);
+ }
+
+ item->string = new_key;
+ item->type = new_type;
+
+ return add_item_to_array(object, item);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
+{
+ return add_item_to_object(object, string, item, &global_hooks, false);
+}
/* Add an item to an object with constant string as key */
-CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
{
- if (!item)
+ return add_item_to_object(object, string, item, &global_hooks, true);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
+{
+ if (array == NULL)
{
- return;
+ return false;
+ }
+
+ return add_item_to_array(array, create_reference(item, &global_hooks));
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
+{
+ if ((object == NULL) || (string == NULL))
+ {
+ return false;
}
- if (!(item->type & cJSON_StringIsConst) && item->string)
+
+ return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false);
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name)
+{
+ cJSON *null = cJSON_CreateNull();
+ if (add_item_to_object(object, name, null, &global_hooks, false))
{
- global_hooks.deallocate(item->string);
+ return null;
}
- item->string = (char*)string;
- item->type |= cJSON_StringIsConst;
- cJSON_AddItemToArray(object, item);
+
+ cJSON_Delete(null);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name)
+{
+ cJSON *true_item = cJSON_CreateTrue();
+ if (add_item_to_object(object, name, true_item, &global_hooks, false))
+ {
+ return true_item;
+ }
+
+ cJSON_Delete(true_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name)
+{
+ cJSON *false_item = cJSON_CreateFalse();
+ if (add_item_to_object(object, name, false_item, &global_hooks, false))
+ {
+ return false_item;
+ }
+
+ cJSON_Delete(false_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean)
+{
+ cJSON *bool_item = cJSON_CreateBool(boolean);
+ if (add_item_to_object(object, name, bool_item, &global_hooks, false))
+ {
+ return bool_item;
+ }
+
+ cJSON_Delete(bool_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number)
+{
+ cJSON *number_item = cJSON_CreateNumber(number);
+ if (add_item_to_object(object, name, number_item, &global_hooks, false))
+ {
+ return number_item;
+ }
+
+ cJSON_Delete(number_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string)
+{
+ cJSON *string_item = cJSON_CreateString(string);
+ if (add_item_to_object(object, name, string_item, &global_hooks, false))
+ {
+ return string_item;
+ }
+
+ cJSON_Delete(string_item);
+ return NULL;
}
-#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
- #pragma GCC diagnostic pop
-#endif
-CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
+CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw)
{
- cJSON_AddItemToArray(array, create_reference(item, &global_hooks));
+ cJSON *raw_item = cJSON_CreateRaw(raw);
+ if (add_item_to_object(object, name, raw_item, &global_hooks, false))
+ {
+ return raw_item;
+ }
+
+ cJSON_Delete(raw_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name)
+{
+ cJSON *object_item = cJSON_CreateObject();
+ if (add_item_to_object(object, name, object_item, &global_hooks, false))
+ {
+ return object_item;
+ }
+
+ cJSON_Delete(object_item);
+ return NULL;
}
-CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
+CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name)
{
- cJSON_AddItemToObject(object, string, create_reference(item, &global_hooks));
+ cJSON *array = cJSON_CreateArray();
+ if (add_item_to_object(object, name, array, &global_hooks, false))
+ {
+ return array;
+ }
+
+ cJSON_Delete(array);
+ return NULL;
}
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item)
@@ -1849,7 +2197,7 @@ CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const it
return NULL;
}
- if (item->prev != NULL)
+ if (item != parent->child)
{
/* not the first element */
item->prev->next = item->next;
@@ -1912,20 +2260,19 @@ CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const
}
/* Replace array/object items with new ones. */
-CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
+CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
{
cJSON *after_inserted = NULL;
if (which < 0)
{
- return;
+ return false;
}
after_inserted = get_array_item(array, (size_t)which);
if (after_inserted == NULL)
{
- cJSON_AddItemToArray(array, newitem);
- return;
+ return add_item_to_array(array, newitem);
}
newitem->next = after_inserted;
@@ -1939,11 +2286,12 @@ CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newit
{
newitem->prev->next = newitem;
}
+ return true;
}
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement)
{
- if ((parent == NULL) || (replacement == NULL))
+ if ((parent == NULL) || (replacement == NULL) || (item == NULL))
{
return false;
}
@@ -1960,14 +2308,20 @@ CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON
{
replacement->next->prev = replacement;
}
- if (replacement->prev != NULL)
- {
- replacement->prev->next = replacement;
- }
if (parent->child == item)
{
parent->child = replacement;
}
+ else
+ { /*
+ * To find the last item in array quickly, we use prev in array.
+ * We can't modify the last item's next pointer where this item was the parent's child
+ */
+ if (replacement->prev != NULL)
+ {
+ replacement->prev->next = replacement;
+ }
+ }
item->next = NULL;
item->prev = NULL;
@@ -1976,24 +2330,42 @@ CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON
return true;
}
-CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
{
if (which < 0)
{
- return;
+ return false;
+ }
+
+ return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
+}
+
+static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive)
+{
+ if ((replacement == NULL) || (string == NULL))
+ {
+ return false;
+ }
+
+ /* replace the name in the replacement */
+ if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL))
+ {
+ cJSON_free(replacement->string);
}
+ replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
+ replacement->type &= ~cJSON_StringIsConst;
- cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
+ return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement);
}
-CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
{
- cJSON_ReplaceItemViaPointer(object, cJSON_GetObjectItem(object, string), newitem);
+ return replace_item_in_object(object, string, newitem, false);
}
-CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem)
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem)
{
- cJSON_ReplaceItemViaPointer(object, cJSON_GetObjectItemCaseSensitive(object, string), newitem);
+ return replace_item_in_object(object, string, newitem, true);
}
/* Create basic types: */
@@ -2030,12 +2402,12 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
return item;
}
-CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b)
+CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean)
{
cJSON *item = cJSON_New_Item(&global_hooks);
if(item)
{
- item->type = b ? cJSON_True : cJSON_False;
+ item->type = boolean ? cJSON_True : cJSON_False;
}
return item;
@@ -2054,7 +2426,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
{
item->valueint = LLONG_MAX;
}
- else if (num <= LLONG_MIN)
+ else if (num <= (double)LLONG_MIN)
{
item->valueint = LLONG_MIN;
}
@@ -2084,6 +2456,39 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
return item;
}
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if (item != NULL)
+ {
+ item->type = cJSON_String | cJSON_IsReference;
+ item->valuestring = (char*)cast_away_const(string);
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if (item != NULL) {
+ item->type = cJSON_Object | cJSON_IsReference;
+ item->child = (cJSON*)cast_away_const(child);
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) {
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if (item != NULL) {
+ item->type = cJSON_Array | cJSON_IsReference;
+ item->child = (cJSON*)cast_away_const(child);
+ }
+
+ return item;
+}
+
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw)
{
cJSON *item = cJSON_New_Item(&global_hooks);
@@ -2131,7 +2536,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
cJSON *p = NULL;
cJSON *a = NULL;
- if (count < 0)
+ if ((count < 0) || (numbers == NULL))
{
return NULL;
}
@@ -2166,7 +2571,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
cJSON *p = NULL;
cJSON *a = NULL;
- if (count < 0)
+ if ((count < 0) || (numbers == NULL))
{
return NULL;
}
@@ -2202,7 +2607,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
cJSON *p = NULL;
cJSON *a = NULL;
- if (count < 0)
+ if ((count < 0) || (numbers == NULL))
{
return NULL;
}
@@ -2231,14 +2636,14 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
return a;
}
-CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count)
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count)
{
size_t i = 0;
cJSON *n = NULL;
cJSON *p = NULL;
cJSON *a = NULL;
- if (count < 0)
+ if ((count < 0) || (strings == NULL))
{
return NULL;
}
@@ -2347,63 +2752,96 @@ fail:
return NULL;
}
-CJSON_PUBLIC(void) cJSON_Minify(char *json)
+static void skip_oneline_comment(char **input)
{
- unsigned char *into = (unsigned char*)json;
- while (*json)
+ *input += static_strlen("//");
+
+ for (; (*input)[0] != '\0'; ++(*input))
{
- if (*json == ' ')
- {
- json++;
- }
- else if (*json == '\t')
- {
- /* Whitespace characters. */
- json++;
+ if ((*input)[0] == '\n') {
+ *input += static_strlen("\n");
+ return;
}
- else if (*json == '\r')
- {
- json++;
- }
- else if (*json=='\n')
+ }
+}
+
+static void skip_multiline_comment(char **input)
+{
+ *input += static_strlen("/*");
+
+ for (; (*input)[0] != '\0'; ++(*input))
+ {
+ if (((*input)[0] == '*') && ((*input)[1] == '/'))
{
- json++;
+ *input += static_strlen("*/");
+ return;
}
- else if ((*json == '/') && (json[1] == '/'))
- {
- /* double-slash comments, to end of line. */
- while (*json && (*json != '\n'))
- {
- json++;
- }
+ }
+}
+
+static void minify_string(char **input, char **output) {
+ (*output)[0] = (*input)[0];
+ *input += static_strlen("\"");
+ *output += static_strlen("\"");
+
+
+ for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) {
+ (*output)[0] = (*input)[0];
+
+ if ((*input)[0] == '\"') {
+ (*output)[0] = '\"';
+ *input += static_strlen("\"");
+ *output += static_strlen("\"");
+ return;
+ } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) {
+ (*output)[1] = (*input)[1];
+ *input += static_strlen("\"");
+ *output += static_strlen("\"");
}
- else if ((*json == '/') && (json[1] == '*'))
+ }
+}
+
+CJSON_PUBLIC(void) cJSON_Minify(char *json)
+{
+ char *into = json;
+
+ if (json == NULL)
+ {
+ return;
+ }
+
+ while (json[0] != '\0')
+ {
+ switch (json[0])
{
- /* multiline comments. */
- while (*json && !((*json == '*') && (json[1] == '/')))
- {
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
json++;
- }
- json += 2;
- }
- else if (*json == '\"')
- {
- /* string literals, which are \" sensitive. */
- *into++ = (unsigned char)*json++;
- while (*json && (*json != '\"'))
- {
- if (*json == '\\')
+ break;
+
+ case '/':
+ if (json[1] == '/')
{
- *into++ = (unsigned char)*json++;
+ skip_oneline_comment(&json);
}
- *into++ = (unsigned char)*json++;
- }
- *into++ = (unsigned char)*json++;
- }
- else
- {
- /* All other characters. */
- *into++ = (unsigned char)*json++;
+ else if (json[1] == '*')
+ {
+ skip_multiline_comment(&json);
+ } else {
+ json++;
+ }
+ break;
+
+ case '\"':
+ minify_string(&json, (char**)&into);
+ break;
+
+ default:
+ into[0] = json[0];
+ json++;
+ into++;
}
}
@@ -2550,7 +2988,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons
return true;
case cJSON_Number:
- if (a->valuedouble == b->valuedouble)
+ if (compare_double(a->valuedouble, b->valuedouble))
{
return true;
}
@@ -2585,16 +3023,22 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons
b_element = b_element->next;
}
+ /* one of the arrays is longer than the other */
+ if (a_element != b_element) {
+ return false;
+ }
+
return true;
}
case cJSON_Object:
{
cJSON *a_element = NULL;
+ cJSON *b_element = NULL;
cJSON_ArrayForEach(a_element, a)
{
/* TODO This has O(n^2) runtime, which is horrible! */
- cJSON *b_element = get_object_item(b, a_element->string, case_sensitive);
+ b_element = get_object_item(b, a_element->string, case_sensitive);
if (b_element == NULL)
{
return false;
@@ -2606,6 +3050,22 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons
}
}
+ /* doing this twice, once on a and b to prevent true comparison if a subset of b
+ * TODO: Do this the proper way, this is just a fix for now */
+ cJSON_ArrayForEach(b_element, b)
+ {
+ a_element = get_object_item(a, b_element->string, case_sensitive);
+ if (a_element == NULL)
+ {
+ return false;
+ }
+
+ if (!cJSON_Compare(b_element, a_element, case_sensitive))
+ {
+ return false;
+ }
+ }
+
return true;
}
diff --git a/src/cjson.h b/src/cjson.h
index fa7cb73..03bc353 100644
--- a/src/cjson.h
+++ b/src/cjson.h
@@ -33,10 +33,60 @@ extern "C"
{
#endif
+#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
+#define __WINDOWS__
+#endif
+
+#ifdef __WINDOWS__
+
+/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
+
+CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
+CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
+CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
+
+For *nix builds that support visibility attribute, you can define similar behavior by
+
+setting default visibility to hidden by adding
+-fvisibility=hidden (for gcc)
+or
+-xldscope=hidden (for sun cc)
+to CFLAGS
+
+then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
+
+*/
+
+#define CJSON_CDECL __cdecl
+#define CJSON_STDCALL __stdcall
+
+/* export symbols by default, this is necessary for copy pasting the C and header file */
+#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
+#define CJSON_EXPORT_SYMBOLS
+#endif
+
+#if defined(CJSON_HIDE_SYMBOLS)
+#define CJSON_PUBLIC(type) type CJSON_STDCALL
+#elif defined(CJSON_EXPORT_SYMBOLS)
+#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
+#elif defined(CJSON_IMPORT_SYMBOLS)
+#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
+#endif
+#else /* !__WINDOWS__ */
+#define CJSON_CDECL
+#define CJSON_STDCALL
+
+#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
+#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
+#else
+#define CJSON_PUBLIC(type) type
+#endif
+#endif
+
/* project version */
#define CJSON_VERSION_MAJOR 1
-#define CJSON_VERSION_MINOR 5
-#define CJSON_VERSION_PATCH 2
+#define CJSON_VERSION_MINOR 7
+#define CJSON_VERSION_PATCH 13
#include <stddef.h>
@@ -79,55 +129,13 @@ typedef struct cJSON
typedef struct cJSON_Hooks
{
- void *(*malloc_fn)(size_t sz);
- void (*free_fn)(void *ptr);
+ /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
+ void *(CJSON_CDECL *malloc_fn)(size_t sz);
+ void (CJSON_CDECL *free_fn)(void *ptr);
} cJSON_Hooks;
typedef int cJSON_bool;
-#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
-#define __WINDOWS__
-#endif
-#ifdef __WINDOWS__
-
-/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 2 define options:
-
-CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
-CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
-CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
-
-For *nix builds that support visibility attribute, you can define similar behavior by
-
-setting default visibility to hidden by adding
--fvisibility=hidden (for gcc)
-or
--xldscope=hidden (for sun cc)
-to CFLAGS
-
-then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
-
-*/
-
-/* export symbols by default, this is necessary for copy pasting the C and header file */
-#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
-#define CJSON_EXPORT_SYMBOLS
-#endif
-
-#if defined(CJSON_HIDE_SYMBOLS)
-#define CJSON_PUBLIC(type) type __stdcall
-#elif defined(CJSON_EXPORT_SYMBOLS)
-#define CJSON_PUBLIC(type) __declspec(dllexport) type __stdcall
-#elif defined(CJSON_IMPORT_SYMBOLS)
-#define CJSON_PUBLIC(type) __declspec(dllimport) type __stdcall
-#endif
-#else /* !WIN32 */
-#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
-#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
-#else
-#define CJSON_PUBLIC(type) type
-#endif
-#endif
-
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
* This is to prevent stack overflows. */
#ifndef CJSON_NESTING_LIMIT
@@ -143,6 +151,12 @@ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
+/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
+/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
+
/* Render a cJSON entity to text for transfer/storage. */
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
/* Render a cJSON entity to text for transfer/storage without any formatting. */
@@ -153,11 +167,11 @@ CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
/* Delete a cJSON entity and all subentities. */
-CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);
+CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
/* Returns the number of items in an array (or object). */
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
-/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
+/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
/* Get item "string" from object. Case insensitive. */
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
@@ -166,6 +180,10 @@ CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *st
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
+/* Check item type and return its value */
+CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item);
+CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *item);
+
/* These functions check the type of an item */
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
@@ -190,24 +208,33 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
-/* These utilities create an Array of count items. */
+/* Create a string where valuestring references a string so
+ * it will not be freed by cJSON_Delete */
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
+/* Create an object/array that only references it's elements so
+ * they will not be freed by cJSON_Delete */
+CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
+CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
+
+/* These utilities create an Array of count items.
+ * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
-CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count);
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
/* Append item to the specified array/object. */
-CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item);
-CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
* writing to `item->string` */
-CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
-CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
-CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
-/* Remove/Detatch items from Arrays/Objects. */
+/* Remove/Detach items from Arrays/Objects. */
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
@@ -217,44 +244,47 @@ CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string)
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
/* Update array items. */
-CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
+CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
-CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
-CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
-CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
/* Duplicate a cJSON item */
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
-need to be released. With recurse!=0, it will duplicate any children connected to the item.
-The item->next and ->prev pointers are always zero on return from Duplicate. */
+ * need to be released. With recurse!=0, it will duplicate any children connected to the item.
+ * The item->next and ->prev pointers are always zero on return from Duplicate. */
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
-
-/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
-/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error. If not, then cJSON_GetErrorPtr() does the job. */
-CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
-
+/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
+ * The input pointer json cannot point to a read-only address area, such as a string constant,
+ * but should point to a readable and writable adress area. */
CJSON_PUBLIC(void) cJSON_Minify(char *json);
-/* Macros for creating things quickly. */
-#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
-#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
-#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
-#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
-#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
-#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
-#define cJSON_AddRawToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateRaw(s))
+/* Helper functions for creating and adding items to an object at the same time.
+ * They return the added item or NULL on failure. */
+CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
+CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
+CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
+CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
+CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
+CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
+CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
+CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
+CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
/* helper for the cJSON_SetNumberValue macro */
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
+/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
+CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
-/* Macro for iterating over an array */
+/* Macro for iterating over an array or object */
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
diff --git a/src/dscp.c b/src/dscp.c
index 329b304..d0c109b 100644
--- a/src/dscp.c
+++ b/src/dscp.c
@@ -27,6 +27,7 @@
#include <stdio.h>
#include <string.h>
+#include <strings.h>
#include <stdlib.h>
#include <inttypes.h>
@@ -42,10 +43,10 @@ const char * iptos2str(int iptos);
* Definitions for IP type of service (ip_tos)
*/
-#if HAVE_NETINET_IN_SYSTM_H
+#ifdef HAVE_NETINET_IN_SYSTM_H
#include <netinet/in_systm.h>
#endif
-#if HAVE_NETINET_IP_H
+#ifdef HAVE_NETINET_IP_H
#include <netinet/ip.h>
#endif
diff --git a/src/iperf.h b/src/iperf.h
index 6ce77f5..6ce77f5 100755..100644
--- a/src/iperf.h
+++ b/src/iperf.h
diff --git a/src/iperf3.1 b/src/iperf3.1
index 8b08fcb..93fe7b9 100644
--- a/src/iperf3.1
+++ b/src/iperf3.1
@@ -1,4 +1,4 @@
-.TH IPERF3 1 "June 2018" ESnet "User Manuals"
+.TH IPERF3 1 "June 2019" ESnet "User Manuals"
.SH NAME
iperf3 \- perform network throughput tests
.SH SYNOPSIS
@@ -278,6 +278,10 @@ number of parallel client streams to run. Note that iperf3 is single threaded, s
reverse the direction of a test, so that the server sends data to the
client
.TP
+.BR --bidir
+test in both directions (normal and reverse), with both the client and
+server sending and receiving data simultaneously
+.TP
.BR -w ", " --window " \fIn\fR[KM]"
window size / socket buffer size (this gets sent to the server and used on that side too)
.TP
diff --git a/src/iperf_api.c b/src/iperf_api.c
index e1bbfa5..ed643b7 100755..100644
--- a/src/iperf_api.c
+++ b/src/iperf_api.c
@@ -1,5 +1,5 @@
/*
- * iperf, Copyright (c) 2014-2019, The Regents of the University of
+ * iperf, Copyright (c) 2014-2020, The Regents of the University of
* California, through Lawrence Berkeley National Laboratory (subject
* to receipt of any required approvals from the U.S. Dept. of
* Energy). All rights reserved.
@@ -63,6 +63,10 @@
#include <sys/cpuset.h>
#endif /* HAVE_CPUSET_SETAFFINITY */
+#if defined(__CYGWIN__) || defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__)
+#define CPU_SETSIZE __CPU_SETSIZE
+#endif /* __CYGWIN__, _WIN32, _WIN64, __WINDOWS__ */
+
#if defined(HAVE_SETPROCESSAFFINITYMASK)
#include <Windows.h>
#endif /* HAVE_SETPROCESSAFFINITYMASK */
@@ -340,6 +344,12 @@ iperf_get_test_no_delay(struct iperf_test *ipt)
return ipt->no_delay;
}
+int
+iperf_get_test_connect_timeout(struct iperf_test *ipt)
+{
+ return ipt->settings->connect_timeout;
+}
+
/************** Setter routines for some fields inside iperf_test *************/
void
@@ -470,7 +480,9 @@ iperf_set_test_role(struct iperf_test *ipt, char role)
{
ipt->role = role;
if (!ipt->reverse) {
- if (role == 'c')
+ if (ipt->bidirectional)
+ ipt->mode = BIDIRECTIONAL;
+ else if (role == 'c')
ipt->mode = SENDER;
else if (role == 's')
ipt->mode = RECEIVER;
@@ -547,13 +559,13 @@ iperf_set_test_unit_format(struct iperf_test *ipt, char unit_format)
void
iperf_set_test_client_username(struct iperf_test *ipt, char *client_username)
{
- ipt->settings->client_username = client_username;
+ ipt->settings->client_username = strdup(client_username);
}
void
iperf_set_test_client_password(struct iperf_test *ipt, char *client_password)
{
- ipt->settings->client_password = client_password;
+ ipt->settings->client_password = strdup(client_password);
}
void
@@ -561,6 +573,18 @@ iperf_set_test_client_rsa_pubkey(struct iperf_test *ipt, char *client_rsa_pubkey
{
ipt->settings->client_rsa_pubkey = load_pubkey_from_base64(client_rsa_pubkey_base64);
}
+
+void
+iperf_set_test_server_authorized_users(struct iperf_test *ipt, char *server_authorized_users)
+{
+ ipt->server_authorized_users = strdup(server_authorized_users);
+}
+
+void
+iperf_set_test_server_rsa_privkey(struct iperf_test *ipt, char *server_rsa_privkey_base64)
+{
+ ipt->server_rsa_private_key = load_privkey_from_base64(server_rsa_privkey_base64);
+}
#endif // HAVE_SSL
void
@@ -590,7 +614,7 @@ iperf_set_test_tos(struct iperf_test *ipt, int tos)
void
iperf_set_test_extra_data(struct iperf_test *ipt, char *dat)
{
- ipt->extra_data = dat;
+ ipt->extra_data = strdup(dat);
}
void
@@ -609,6 +633,13 @@ iperf_set_test_no_delay(struct iperf_test* ipt, int no_delay)
ipt->no_delay = no_delay;
}
+void
+iperf_set_test_connect_timeout(struct iperf_test* ipt, int ct)
+{
+ ipt->settings->connect_timeout = ct;
+}
+
+
/********************** Get/set test protocol structure ***********************/
struct protocol *
@@ -755,7 +786,7 @@ iperf_on_connect(struct iperf_test *test)
}
}
if (test->settings->rate)
- iperf_printf(test, " Target Bitrate: %llu\n", test->settings->rate);
+ iperf_printf(test, " Target Bitrate: %"PRIu64"\n", test->settings->rate);
}
}
@@ -1263,12 +1294,6 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
else if (iperf_getpass(&client_password, &s, stdin) < 0){
return -1;
}
-
- if (strlen(client_username) > 20 || strlen(client_password) > 20){
- i_errno = IESETCLIENTAUTH;
- return -1;
- }
-
if (test_load_pubkey_from_file(client_rsa_public_key) < 0){
i_errno = IESETCLIENTAUTH;
return -1;
@@ -1397,7 +1422,7 @@ iperf_check_throttle(struct iperf_stream *sp, struct iperf_time *nowP)
double seconds;
uint64_t bits_per_second;
- if (sp->test->done)
+ if (sp->test->done || sp->test->settings->rate == 0 || sp->test->settings->burst != 0)
return;
iperf_time_diff(&sp->result->start_time_fixed, nowP, &temp_time);
seconds = iperf_time_in_secs(&temp_time);
@@ -1442,8 +1467,7 @@ iperf_send(struct iperf_test *test, fd_set *write_setP)
streams_active = 1;
test->bytes_sent += r;
++test->blocks_sent;
- if (test->settings->rate != 0 && test->settings->burst == 0)
- iperf_check_throttle(sp, &now);
+ iperf_check_throttle(sp, &now);
if (multisend > 1 && test->settings->bytes != 0 && test->bytes_sent >= test->settings->bytes)
break;
if (multisend > 1 && test->settings->blocks != 0 && test->blocks_sent >= test->settings->blocks)
@@ -1559,15 +1583,18 @@ int test_is_authorized(struct iperf_test *test){
if (test->settings->authtoken){
char *username = NULL, *password = NULL;
time_t ts;
- decode_auth_setting(test->debug, test->settings->authtoken, test->server_rsa_private_key, &username, &password, &ts);
+ int rc = decode_auth_setting(test->debug, test->settings->authtoken, test->server_rsa_private_key, &username, &password, &ts);
+ if (rc) {
+ return -1;
+ }
int ret = check_authentication(username, password, ts, test->server_authorized_users);
if (ret == 0){
- iperf_printf(test, report_authetication_successed, username, ts);
+ iperf_printf(test, report_authentication_succeeded, username, ts);
free(username);
free(password);
return 0;
} else {
- iperf_printf(test, report_authetication_failed, username, ts);
+ iperf_printf(test, report_authentication_failed, username, ts);
free(username);
free(password);
return -1;
@@ -1730,15 +1757,25 @@ send_parameters(struct iperf_test *test)
if (test->repeating_payload)
cJSON_AddNumberToObject(j, "repeating_payload", test->repeating_payload);
#if defined(HAVE_SSL)
- if (test->settings->client_username && test->settings->client_password && test->settings->client_rsa_pubkey){
- encode_auth_setting(test->settings->client_username, test->settings->client_password, test->settings->client_rsa_pubkey, &test->settings->authtoken);
- cJSON_AddStringToObject(j, "authtoken", test->settings->authtoken);
- }
+ /* Send authentication parameters */
+ if (test->settings->client_username && test->settings->client_password && test->settings->client_rsa_pubkey){
+ int rc = encode_auth_setting(test->settings->client_username, test->settings->client_password, test->settings->client_rsa_pubkey, &test->settings->authtoken);
+
+ if (rc) {
+ cJSON_Delete(j);
+ i_errno = IESENDPARAMS;
+ return -1;
+ }
+
+ cJSON_AddStringToObject(j, "authtoken", test->settings->authtoken);
+ }
#endif // HAVE_SSL
cJSON_AddStringToObject(j, "client_version", IPERF_VERSION);
if (test->debug) {
- printf("send_parameters:\n%s\n", cJSON_Print(j));
+ char *str = cJSON_Print(j);
+ printf("send_parameters:\n%s\n", str);
+ cJSON_free(str);
}
if (JSON_write(test->ctrl_sck, j) < 0) {
@@ -1768,7 +1805,7 @@ get_parameters(struct iperf_test *test)
char *str;
str = cJSON_Print(j);
printf("get_parameters:\n%s\n", str );
- free(str);
+ cJSON_free(str);
}
if ((j_p = cJSON_GetObjectItem(j, "tcp")) != NULL)
@@ -1833,8 +1870,8 @@ get_parameters(struct iperf_test *test)
#endif //HAVE_SSL
if (test->mode && test->protocol->id == Ptcp && has_tcpinfo_retransmits())
test->sender_has_retransmits = 1;
- if (test->settings->rate)
- cJSON_AddNumberToObject(test->json_start, "target_bitrate", test->settings->rate);
+ if (test->settings->rate)
+ cJSON_AddNumberToObject(test->json_start, "target_bitrate", test->settings->rate);
cJSON_Delete(j);
}
return r;
@@ -1935,7 +1972,7 @@ send_results(struct iperf_test *test)
if (r == 0 && test->debug) {
char *str = cJSON_Print(j);
printf("send_results\n%s\n", str);
- free(str);
+ cJSON_free(str);
}
if (r == 0 && JSON_write(test->ctrl_sck, j) < 0) {
i_errno = IESENDRESULTS;
@@ -1993,7 +2030,7 @@ get_results(struct iperf_test *test)
if (test->debug) {
char *str = cJSON_Print(j);
printf("get_results\n%s\n", str);
- free(str);
+ cJSON_free(str);
}
test->remote_cpu_util[0] = j_cpu_util_total->valuedouble;
@@ -2130,7 +2167,7 @@ JSON_write(int fd, cJSON *json)
if (Nwrite(fd, str, hsize, Ptcp) < 0)
r = -1;
}
- free(str);
+ cJSON_free(str);
}
return r;
}
@@ -3417,7 +3454,9 @@ iperf_print_results(struct iperf_test *test)
/* Print server output if we're on the client and it was requested/provided */
if (test->role == 'c' && iperf_get_test_get_server_output(test) && !test->json_output) {
if (test->json_server_output) {
- iperf_printf(test, "\nServer JSON output:\n%s\n", cJSON_Print(test->json_server_output));
+ char *str = cJSON_Print(test->json_server_output);
+ iperf_printf(test, "\nServer JSON output:\n%s\n", str);
+ cJSON_free(str);
cJSON_Delete(test->json_server_output);
test->json_server_output = NULL;
}
@@ -3849,9 +3888,15 @@ diskfile_recv(struct iperf_stream *sp)
void
iperf_catch_sigend(void (*handler)(int))
{
+#ifdef SIGINT
signal(SIGINT, handler);
+#endif
+#ifdef SIGTERM
signal(SIGTERM, handler);
+#endif
+#ifdef SIGHUP
signal(SIGHUP, handler);
+#endif
}
/**
@@ -3995,6 +4040,8 @@ iperf_json_finish(struct iperf_test *test)
return -1;
fprintf(test->outfile, "%s\n", test->json_output_string);
iflush(test);
+ cJSON_free(test->json_output_string);
+ test->json_output_string = NULL;
cJSON_Delete(test->json_top);
test->json_top = test->json_start = test->json_connected = test->json_intervals = test->json_server_output = test->json_end = NULL;
return 0;
diff --git a/src/iperf_api.h b/src/iperf_api.h
index f9f964e..3770b37 100755..100644
--- a/src/iperf_api.h
+++ b/src/iperf_api.h
@@ -1,5 +1,5 @@
/*
- * iperf, Copyright (c) 2014-2019, The Regents of the University of
+ * iperf, Copyright (c) 2014-2020, The Regents of the University of
* California, through Lawrence Berkeley National Laboratory (subject
* to receipt of any required approvals from the U.S. Dept. of
* Energy). All rights reserved.
@@ -128,6 +128,7 @@ int iperf_get_test_tos( struct iperf_test* ipt );
char* iperf_get_extra_data( struct iperf_test* ipt );
char* iperf_get_iperf_version(void);
int iperf_get_test_no_delay( struct iperf_test* ipt );
+int iperf_get_test_connect_timeout( struct iperf_test* ipt );
/* Setter routines for some fields inside iperf_test. */
void iperf_set_verbose( struct iperf_test* ipt, int verbose );
@@ -160,7 +161,7 @@ void iperf_set_test_bind_address( struct iperf_test* ipt, char *bind_address );
void iperf_set_test_udp_counters_64bit( struct iperf_test* ipt, int udp_counters_64bit );
void iperf_set_test_one_off( struct iperf_test* ipt, int one_off );
void iperf_set_test_tos( struct iperf_test* ipt, int tos );
-void iperf_set_extra_data( struct iperf_test* ipt, char *dat);
+void iperf_set_test_extra_data( struct iperf_test* ipt, char *dat );
void iperf_set_test_bidirectional( struct iperf_test* ipt, int bidirectional);
void iperf_set_test_no_delay( struct iperf_test* ipt, int no_delay);
@@ -168,8 +169,12 @@ void iperf_set_test_no_delay( struct iperf_test* ipt, int no_delay);
void iperf_set_test_client_username(struct iperf_test *ipt, char *client_username);
void iperf_set_test_client_password(struct iperf_test *ipt, char *client_password);
void iperf_set_test_client_rsa_pubkey(struct iperf_test *ipt, char *client_rsa_pubkey_base64);
+void iperf_set_test_server_authorized_users(struct iperf_test *ipt, char *server_authorized_users);
+void iperf_set_test_server_rsa_privkey(struct iperf_test *ipt, char *server_rsa_privkey_base64);
#endif // HAVE_SSL
+void iperf_set_test_connect_timeout(struct iperf_test *ipt, int ct);
+
/**
* exchange_parameters - handles the param_Exchange part for client
*
diff --git a/src/iperf_auth.c b/src/iperf_auth.c
index 9965e19..46211e0 100644
--- a/src/iperf_auth.c
+++ b/src/iperf_auth.c
@@ -1,5 +1,5 @@
/*
- * iperf, Copyright (c) 2014-2018, The Regents of the University of
+ * iperf, Copyright (c) 2014-2020, The Regents of the University of
* California, through Lawrence Berkeley National Laboratory (subject
* to receipt of any required approvals from the U.S. Dept. of
* Energy). All rights reserved.
@@ -43,6 +43,9 @@
#include <openssl/pem.h>
#include <openssl/sha.h>
#include <openssl/buffer.h>
+#include <openssl/err.h>
+
+const char *auth_text_format = "user: %s\npwd: %s\nts: %ld";
void sha256(const char *string, char outputBuffer[65])
{
@@ -151,7 +154,6 @@ int Base64Decode(const char* b64message, unsigned char** buffer, size_t* length)
return (0); //success
}
-
EVP_PKEY *load_pubkey_from_file(const char *file) {
BIO *key = NULL;
EVP_PKEY *pkey = NULL;
@@ -159,7 +161,7 @@ EVP_PKEY *load_pubkey_from_file(const char *file) {
if (file) {
key = BIO_new_file(file, "r");
pkey = PEM_read_bio_PUBKEY(key, NULL, NULL, NULL);
-
+
BIO_free(key);
}
return (pkey);
@@ -173,6 +175,7 @@ EVP_PKEY *load_pubkey_from_base64(const char *buffer) {
BIO* bio = BIO_new(BIO_s_mem());
BIO_write(bio, key, key_len);
EVP_PKEY *pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
+ BIO_free(bio);
return (pkey);
}
@@ -189,6 +192,17 @@ EVP_PKEY *load_privkey_from_file(const char *file) {
return (pkey);
}
+EVP_PKEY *load_privkey_from_base64(const char *buffer) {
+ unsigned char *key = NULL;
+ size_t key_len;
+ Base64Decode(buffer, &key, &key_len);
+
+ BIO* bio = BIO_new(BIO_s_mem());
+ BIO_write(bio, key, key_len);
+ EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
+ BIO_free(bio);
+ return (pkey);
+}
int test_load_pubkey_from_file(const char *file){
EVP_PKEY *key = load_pubkey_from_file(file);
@@ -227,6 +241,11 @@ int encrypt_rsa_message(const char *plaintext, EVP_PKEY *public_key, unsigned ch
OPENSSL_free(rsa_buffer);
BIO_free(bioBuff);
+ if (encryptedtext_len < 0) {
+ /* We probably shoudln't be printing stuff like this */
+ fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), NULL));
+ }
+
return encryptedtext_len;
}
@@ -249,17 +268,36 @@ int decrypt_rsa_message(const unsigned char *encryptedtext, const int encryptedt
OPENSSL_free(rsa_buffer);
BIO_free(bioBuff);
+ if (plaintext_len < 0) {
+ /* We probably shoudln't be printing stuff like this */
+ fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), NULL));
+ }
+
return plaintext_len;
}
int encode_auth_setting(const char *username, const char *password, EVP_PKEY *public_key, char **authtoken){
time_t t = time(NULL);
time_t utc_seconds = mktime(localtime(&t));
- char text[150];
- sprintf (text, "user: %s\npwd: %s\nts: %ld", username, password, utc_seconds);
+
+ /*
+ * Compute a pessimistic/conservative estimate of storage required.
+ * It's OK to allocate too much storage but too little is bad.
+ */
+ const int text_len = strlen(auth_text_format) + strlen(username) + strlen(password) + 32;
+ char *text = (char *) calloc(text_len, sizeof(char));
+ if (text == NULL) {
+ return -1;
+ }
+ snprintf(text, text_len, auth_text_format, username, password, utc_seconds);
+
unsigned char *encrypted = NULL;
int encrypted_len;
encrypted_len = encrypt_rsa_message(text, public_key, &encrypted);
+ free(text);
+ if (encrypted_len < 0) {
+ return -1;
+ }
Base64Encode(encrypted, encrypted_len, authtoken);
OPENSSL_free(encrypted);
@@ -274,19 +312,36 @@ int decode_auth_setting(int enable_debug, char *authtoken, EVP_PKEY *private_key
unsigned char *plaintext = NULL;
int plaintext_len;
plaintext_len = decrypt_rsa_message(encrypted_b64, encrypted_len_b64, private_key, &plaintext);
- plaintext[plaintext_len] = '\0';
free(encrypted_b64);
+ if (plaintext_len < 0) {
+ return -1;
+ }
+ plaintext[plaintext_len] = '\0';
+
+ char *s_username, *s_password;
+ s_username = (char *) calloc(plaintext_len, sizeof(char));
+ if (s_username == NULL) {
+ return -1;
+ }
+ s_password = (char *) calloc(plaintext_len, sizeof(char));
+ if (s_password == NULL) {
+ free(s_username);
+ return -1;
+ }
+
+ int rc = sscanf((char *) plaintext, auth_text_format, s_username, s_password, ts);
+ if (rc != 3) {
+ free(s_password);
+ free(s_username);
+ return -1;
+ }
- char s_username[20], s_password[20];
- sscanf ((char *)plaintext,"user: %s\npwd: %s\nts: %ld", s_username, s_password, ts);
if (enable_debug) {
printf("Auth Token Content:\n%s\n", plaintext);
printf("Auth Token Credentials:\n--> %s %s\n", s_username, s_password);
}
- *username = (char *) calloc(21, sizeof(char));
- *password = (char *) calloc(21, sizeof(char));
- strncpy(*username, s_username, 20);
- strncpy(*password, s_password, 20);
+ *username = s_username;
+ *password = s_password;
OPENSSL_free(plaintext);
return (0);
}
diff --git a/src/iperf_auth.h b/src/iperf_auth.h
index 0c6fb0f..0dd6c4c 100644
--- a/src/iperf_auth.h
+++ b/src/iperf_auth.h
@@ -34,6 +34,7 @@ int test_load_private_key_from_file(const char *private_keyfile);
EVP_PKEY *load_pubkey_from_file(const char *file);
EVP_PKEY *load_pubkey_from_base64(const char *buffer);
EVP_PKEY *load_privkey_from_file(const char *file);
+EVP_PKEY *load_privkey_from_base64(const char *buffer);
int encode_auth_setting(const char *username, const char *password, EVP_PKEY *public_key, char **authtoken);
int decode_auth_setting(int enable_debug, const char *authtoken, EVP_PKEY *private_key, char **username, char **password, time_t *ts);
int check_authentication(const char *username, const char *password, const time_t ts, const char *filename);
diff --git a/src/iperf_error.c b/src/iperf_error.c
index fd3cccc..c6e5ee4 100644
--- a/src/iperf_error.c
+++ b/src/iperf_error.c
@@ -1,5 +1,5 @@
/*
- * iperf, Copyright (c) 2014-2019, The Regents of the University of
+ * iperf, Copyright (c) 2014-2020, The Regents of the University of
* California, through Lawrence Berkeley National Laboratory (subject
* to receipt of any required approvals from the U.S. Dept. of
* Energy). All rights reserved.
@@ -134,10 +134,10 @@ iperf_strerror(int int_errno)
snprintf(errstr, len, "bad TOS value (must be between 0 and 255 inclusive)");
break;
case IESETCLIENTAUTH:
- snprintf(errstr, len, "you must specify username (max 20 chars), password (max 20 chars) and a path to a valid public rsa client to be used");
+ snprintf(errstr, len, "you must specify a username, password, and path to a valid RSA public key");
break;
case IESETSERVERAUTH:
- snprintf(errstr, len, "you must specify path to a valid private rsa server to be used and a user credential file");
+ snprintf(errstr, len, "you must specify a path to a valid RSA private key and a user credential file");
break;
case IEBADFORMAT:
snprintf(errstr, len, "bad format specifier (valid formats are in the set [kmgtKMGT])");
diff --git a/src/iperf_locale.c b/src/iperf_locale.c
index 0d8a7ec..2dd5a5b 100644
--- a/src/iperf_locale.c
+++ b/src/iperf_locale.c
@@ -1,5 +1,5 @@
/*---------------------------------------------------------------
- * iperf, Copyright (c) 2014-2018, The Regents of the University of
+ * iperf, Copyright (c) 2014-2020, The Regents of the University of
* California, through Lawrence Berkeley National Laboratory (subject
* to receipt of any required approvals from the U.S. Dept. of
* Energy). All rights reserved.
@@ -272,10 +272,10 @@ const char report_time[] =
const char report_connecting[] =
"Connecting to host %s, port %d\n";
-const char report_authetication_successed[] =
+const char report_authentication_succeeded[] =
"Authentication successed for user '%s' ts %ld\n";
-const char report_authetication_failed[] =
+const char report_authentication_failed[] =
"Authentication failed for user '%s' ts %ld\n";
const char report_reverse[] =
diff --git a/src/iperf_locale.h b/src/iperf_locale.h
index ad784a6..15bdcdb 100644
--- a/src/iperf_locale.h
+++ b/src/iperf_locale.h
@@ -1,5 +1,5 @@
/*
- * iperf, Copyright (c) 2014-2018, The Regents of the University of
+ * iperf, Copyright (c) 2014-2020, The Regents of the University of
* California, through Lawrence Berkeley National Laboratory (subject
* to receipt of any required approvals from the U.S. Dept. of
* Energy). All rights reserved.
@@ -54,8 +54,8 @@ extern const char report_reverse[] ;
extern const char report_accepted[] ;
extern const char report_cookie[] ;
extern const char report_connected[] ;
-extern const char report_authetication_successed[] ;
-extern const char report_authetication_failed[] ;
+extern const char report_authentication_succeeded[] ;
+extern const char report_authentication_failed[] ;
extern const char report_window[] ;
extern const char report_autotune[] ;
extern const char report_omit_done[] ;
diff --git a/src/iperf_sctp.c b/src/iperf_sctp.c
index 06e1e23..0bc98ba 100644
--- a/src/iperf_sctp.c
+++ b/src/iperf_sctp.c
@@ -131,12 +131,14 @@ iperf_sctp_accept(struct iperf_test * test)
if (Nread(s, cookie, COOKIE_SIZE, Psctp) < 0) {
i_errno = IERECVCOOKIE;
+ close(s);
return -1;
}
- if (strcmp(test->cookie, cookie) != 0) {
+ if (strncmp(test->cookie, cookie, COOKIE_SIZE) != 0) {
if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Psctp) < 0) {
i_errno = IESENDMESSAGE;
+ close(s);
return -1;
}
close(s);
@@ -189,6 +191,26 @@ iperf_sctp_listen(struct iperf_test *test)
return -1;
}
+ if ((opt = test->settings->socket_bufsize)) {
+ int saved_errno;
+ if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
+ saved_errno = errno;
+ close(s);
+ freeaddrinfo(res);
+ errno = saved_errno;
+ i_errno = IESETBUF;
+ return -1;
+ }
+ if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
+ saved_errno = errno;
+ close(s);
+ freeaddrinfo(res);
+ errno = saved_errno;
+ i_errno = IESETBUF;
+ return -1;
+ }
+ }
+
#if defined(IPV6_V6ONLY) && !defined(__OpenBSD__)
if (res->ai_family == AF_INET6 && (test->settings->domain == AF_UNSPEC ||
test->settings->domain == AF_INET6)) {
@@ -220,9 +242,11 @@ iperf_sctp_listen(struct iperf_test *test)
/* servers must call sctp_bindx() _instead_ of bind() */
if (!TAILQ_EMPTY(&test->xbind_addrs)) {
- freeaddrinfo(res);
- if (iperf_sctp_bindx(test, s, IPERF_SCTP_SERVER))
+ if (iperf_sctp_bindx(test, s, IPERF_SCTP_SERVER)) {
+ close(s);
+ freeaddrinfo(res);
return -1;
+ }
} else
if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
saved_errno = errno;
@@ -292,6 +316,26 @@ iperf_sctp_connect(struct iperf_test *test)
return -1;
}
+ if ((opt = test->settings->socket_bufsize)) {
+ int saved_errno;
+ if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
+ saved_errno = errno;
+ close(s);
+ freeaddrinfo(server_res);
+ errno = saved_errno;
+ i_errno = IESETBUF;
+ return -1;
+ }
+ if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
+ saved_errno = errno;
+ close(s);
+ freeaddrinfo(server_res);
+ errno = saved_errno;
+ i_errno = IESETBUF;
+ return -1;
+ }
+ }
+
/*
* Various ways to bind the local end of the connection.
* 1. --bind (with or without --cport).
@@ -433,8 +477,11 @@ iperf_sctp_connect(struct iperf_test *test)
/* clients must call bind() followed by sctp_bindx() before connect() */
if (!TAILQ_EMPTY(&test->xbind_addrs)) {
- if (iperf_sctp_bindx(test, s, IPERF_SCTP_CLIENT))
+ if (iperf_sctp_bindx(test, s, IPERF_SCTP_CLIENT)) {
+ freeaddrinfo(server_res);
+ close(s);
return -1;
+ }
}
/* TODO support sctp_connectx() to avoid heartbeating. */
@@ -446,12 +493,12 @@ iperf_sctp_connect(struct iperf_test *test)
i_errno = IESTREAMCONNECT;
return -1;
}
- freeaddrinfo(server_res);
/* Send cookie for verification */
if (Nwrite(s, test->cookie, COOKIE_SIZE, Psctp) < 0) {
saved_errno = errno;
close(s);
+ freeaddrinfo(server_res);
errno = saved_errno;
i_errno = IESENDCOOKIE;
return -1;
@@ -475,6 +522,7 @@ iperf_sctp_connect(struct iperf_test *test)
return -1;
}
+ freeaddrinfo(server_res);
return s;
#else
i_errno = IENOSCTP;
diff --git a/src/iperf_tcp.c b/src/iperf_tcp.c
index 232aaa1..47252d0 100644
--- a/src/iperf_tcp.c
+++ b/src/iperf_tcp.c
@@ -29,6 +29,7 @@
#include <string.h>
#include <errno.h>
#include <unistd.h>
+#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
diff --git a/src/iperf_udp.c b/src/iperf_udp.c
index 3d37dab..ab6be5e 100644
--- a/src/iperf_udp.c
+++ b/src/iperf_udp.c
@@ -1,5 +1,5 @@
/*
- * iperf, Copyright (c) 2014-2018, The Regents of the University of
+ * iperf, Copyright (c) 2014-2020, The Regents of the University of
* California, through Lawrence Berkeley National Laboratory (subject
* to receipt of any required approvals from the U.S. Dept. of
* Energy). All rights reserved.
@@ -30,6 +30,7 @@
#include <errno.h>
#include <unistd.h>
#include <assert.h>
+#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
@@ -65,6 +66,7 @@ iperf_udp_recv(struct iperf_stream *sp)
uint64_t pcount;
int r;
int size = sp->settings->blksize;
+ int first_packet = 0;
double transit = 0, d = 0;
struct iperf_time sent_time, arrival_time, temp_time;
@@ -80,9 +82,19 @@ iperf_udp_recv(struct iperf_stream *sp)
/* Only count bytes received while we're in the correct state. */
if (sp->test->state == TEST_RUNNING) {
+
+ /*
+ * For jitter computation below, it's important to know if this
+ * packet is the first packet received.
+ */
+ if (sp->result->bytes_received == 0) {
+ first_packet = 1;
+ }
+
sp->result->bytes_received += r;
sp->result->bytes_received_this_interval += r;
+ /* Dig the various counters out of the incoming UDP packet */
if (sp->test->udp_counters_64bit) {
memcpy(&sec, sp->buffer, sizeof(sec));
memcpy(&usec, sp->buffer+4, sizeof(usec));
@@ -149,7 +161,7 @@ iperf_udp_recv(struct iperf_stream *sp)
/* Log the out-of-order packet */
if (sp->test->debug)
- fprintf(stderr, "OUT OF ORDER - incoming packet sequence %" PRIu64 " but expected sequence %d on stream %d", pcount, sp->packet_count, sp->socket);
+ fprintf(stderr, "OUT OF ORDER - incoming packet sequence %" PRIu64 " but expected sequence %d on stream %d", pcount, sp->packet_count + 1, sp->socket);
}
/*
@@ -167,6 +179,11 @@ iperf_udp_recv(struct iperf_stream *sp)
iperf_time_diff(&arrival_time, &sent_time, &temp_time);
transit = iperf_time_in_secs(&temp_time);
+
+ /* Hack to handle the first packet by initializing prev_transit. */
+ if (first_packet)
+ sp->prev_transit = transit;
+
d = transit - sp->prev_transit;
if (d < 0)
d = -d;
diff --git a/src/main.c b/src/main.c
index fe10a2f..c82ee43 100644
--- a/src/main.c
+++ b/src/main.c
@@ -44,9 +44,10 @@
#include "iperf.h"
#include "iperf_api.h"
-#include "units.h"
+#include "iperf_util.h"
#include "iperf_locale.h"
#include "net.h"
+#include "units.h"
static int run(struct iperf_test *test);
diff --git a/src/net.c b/src/net.c
index 96fb7ed..b475ed0 100644
--- a/src/net.c
+++ b/src/net.c
@@ -29,6 +29,7 @@
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
+#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
diff --git a/src/private.pem b/src/private.pem
new file mode 100644
index 0000000..8b1c5b6
--- /dev/null
+++ b/src/private.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAwVbvPf/eDIZKmEVth9+VPgSx1RkXOAPCJ5tl51bcYoy9P10N
+noutsTK/64VclIuyUDUdAw81Vu5tYRcBeB8Jllp02xL8kPo0IROsT3wmMYbPziUG
+/I2988sAP9mL8QbtKydnADHMikfadfyPkfxW2naFtquWT/vKKVkhC2LHJyTpmAVj
+pp6R9LDDu/YY0/kb5DvYPpe62xgNWjNVIhABu3R+StAAL25SaLXuaGSVpDe6Sphn
+TqVf+LmKCkZmSMSfQoozXomNyFpLU8ODoV3QyHYi6QSWWFtU6gu0uso/9pfRFjbN
+GV9lxokKNz/cZGyu0SFddMiTGrt24NROi0RHwwIDAQABAoIBACVG+cHef5WyntdV
+K5UzCrd2eEM6HzvxnZG9aJx+JufpcuOwsVuMWuT7f/2NLRiHBs5oLzvTxtkIB5bc
+tK/QbCzNLBLBSmk5lKt7+5EnwsVx1MdOZFZ1jdZfoaCt9Ul3qGrVogprj6Bp0jlF
+hPkEyko85/McilLJnWTzhmeHmBZ3tOJ9LWHgVdXGXZx/pBuxZ+UB/xgZdvdZK86F
+xndWqD8lvfpoSsVwzCORdXvQWs78CtT2KXYvt8S6mrLMoIoHLO/1rwwKKoZfFuja
+NouN36PGaSo4/9O1d11/s9zwdJH3ShozY0Fao8I3XhdH0uvTirmAEPh7U1Lo71pP
+ksUvbUECgYEA/7p1Bg/XsSK72KgJ695B2hi8g9+wv0eKCpGwkKJQZKE338it8zIn
++JMaeDjObLhb4B2QP/3iL0mdU2mJzm0X8hYCKqBdyICb9wixznLLAej+uw2j60Ef
+tlGenCqAkVL3pRS5txztNhFsXx3JwxCSj4zwmVm5oyxkpAeuwvZ1cPkCgYEAwYuC
+6nPlRf6GEf/MuHCziaCCPrDm1u472uspxHn41crw6BaMl5xcmr0Z8O7heOtlVmMl
+Mn3gfIbd/NGyjs8ejmWcO5mZHtESGM/zAaVyu7bn3ij37OEndbEpZsCpRtxvtaji
+MTMwhdV2xteJ0+KCtg66ziSyJv3krQTEW8DZKZsCgYB8BcnLbtOErPu9T4HASsJV
+K7oBmvL1UZS5G38uJgonQ6j9dy4lzCVmgLFNrP8v6xljz/Ktlkuj82fBlGWpH2+F
+kPbsBWp2WylI3YaeQT4DZyRjQ3JEHglrOppZ0qMX180S2sJW9Eh2+Gw+lQvM9rSd
+uhTVypYldNo6Ux+GnlDGwQKBgQC/6W4uvCyjcvXN8y8z08yysw1yzEaY6DFBqd0I
+jUlH9Ktb9sABtXG9nbSTSssX85HQTw8bOeXWlISZo/TB1m4eFHMORgemnviq0cfL
+4hoaOAtCJq1vnPJbqQe8c11mfj3mi0d+MZvzmO7ly+NGzlt92q0wqwJb13VgelGa
+CWdL8QKBgQD1ABK8WJuMowihrQsLaUxNO/1hsN8CP/rjoi9D5NdSFt5zzcC3D/RA
+m42ScOaAFIh44Js5aAROvbDqIlelhwRlmutP/lYyQRZDZm7X6u/bKuqK4H/sM6ZB
+SICe2eWFvbKexI7QnreRltOWIFrNoZy9FdELM8DS+kePAlVt7c83Uw==
+-----END RSA PRIVATE KEY-----
diff --git a/src/public.pem b/src/public.pem
new file mode 100644
index 0000000..71f4f13
--- /dev/null
+++ b/src/public.pem
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwVbvPf/eDIZKmEVth9+V
+PgSx1RkXOAPCJ5tl51bcYoy9P10NnoutsTK/64VclIuyUDUdAw81Vu5tYRcBeB8J
+llp02xL8kPo0IROsT3wmMYbPziUG/I2988sAP9mL8QbtKydnADHMikfadfyPkfxW
+2naFtquWT/vKKVkhC2LHJyTpmAVjpp6R9LDDu/YY0/kb5DvYPpe62xgNWjNVIhAB
+u3R+StAAL25SaLXuaGSVpDe6SphnTqVf+LmKCkZmSMSfQoozXomNyFpLU8ODoV3Q
+yHYi6QSWWFtU6gu0uso/9pfRFjbNGV9lxokKNz/cZGyu0SFddMiTGrt24NROi0RH
+wwIDAQAB
+-----END PUBLIC KEY-----
diff --git a/src/t_api.c b/src/t_api.c
index 0669917..f5e0984 100644
--- a/src/t_api.c
+++ b/src/t_api.c
@@ -1,5 +1,5 @@
/*
- * iperf, Copyright (c) 2017, The Regents of the University of
+ * iperf, Copyright (c) 2017-2020, The Regents of the University of
* California, through Lawrence Berkeley National Laboratory (subject
* to receipt of any required approvals from the U.S. Dept. of
* Energy). All rights reserved.
@@ -45,9 +45,21 @@ int
main(int argc, char **argv)
{
const char *ver;
+ struct iperf_test *test;
+ int sint, gint;
ver = iperf_get_iperf_version();
assert(strcmp(ver, IPERF_VERSION) == 0);
+ test = iperf_new_test();
+ assert(test != NULL);
+
+ iperf_defaults(test);
+
+ sint = 10;
+ iperf_set_test_connect_timeout(test, sint);
+ gint = iperf_get_test_connect_timeout(test);
+ assert(sint == gint);
+
return 0;
}
diff --git a/src/t_auth.c b/src/t_auth.c
new file mode 100644
index 0000000..ff9cffe
--- /dev/null
+++ b/src/t_auth.c
@@ -0,0 +1,125 @@
+/*
+ * iperf, Copyright (c) 2020, The Regents of the University of
+ * California, through Lawrence Berkeley National Laboratory (subject
+ * to receipt of any required approvals from the U.S. Dept. of
+ * Energy). All rights reserved.
+ *
+ * If you have questions about your rights to use or distribute this
+ * software, please contact Berkeley Lab's Technology Transfer
+ * Department at TTD@lbl.gov.
+ *
+ * NOTICE. This software is owned by the U.S. Department of Energy.
+ * As such, the U.S. Government has been granted for itself and others
+ * acting on its behalf a paid-up, nonexclusive, irrevocable,
+ * worldwide license in the Software to reproduce, prepare derivative
+ * works, and perform publicly and display publicly. Beginning five
+ * (5) years after the date permission to assert copyright is obtained
+ * from the U.S. Department of Energy, and subject to any subsequent
+ * five (5) year renewals, the U.S. Government is granted for itself
+ * and others acting on its behalf a paid-up, nonexclusive,
+ * irrevocable, worldwide license in the Software to reproduce,
+ * prepare derivative works, distribute copies to the public, perform
+ * publicly and display publicly, and to permit others to do so.
+ *
+ * This code is distributed under a BSD style license, see the LICENSE
+ * file for complete information.
+ */
+#include "iperf_config.h"
+
+#include <assert.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+
+#include "iperf.h"
+#include "iperf_api.h"
+#if defined(HAVE_SSL)
+#include "iperf_auth.h"
+#endif /* HAVE_SSL */
+
+#include "version.h"
+
+#include "units.h"
+
+#if defined(HAVE_SSL)
+int test_authtoken(const char *authUser, const char *authPassword, EVP_PKEY *pubkey, EVP_PKEY *privkey);
+
+int
+main(int argc, char **argv)
+{
+ /* sha256 */
+ void sha256(const char *string, char outputBuffer[65]);
+ const char sha256String[] = "This is a SHA256 test.";
+ const char sha256Digest[] = "4816482f8b4149f687a1a33d61a0de6b611364ec0fb7adffa59ff2af672f7232"; /* echo -n "This is a SHA256 test." | shasum -a256 */
+ char sha256Output[65];
+
+ sha256(sha256String, sha256Output);
+ assert(strcmp(sha256Output, sha256Digest) == 0);
+
+ /* Base64{Encode,Decode} */
+ int Base64Encode(const unsigned char* buffer, const size_t length, char** b64text);
+ int Base64Decode(const char* b64message, unsigned char** buffer, size_t* length);
+ const char base64String[] = "This is a Base64 test.";
+ char *base64Text;
+ char *base64Decode;
+ size_t base64DecodeLength;
+ const char base64EncodeCheck[] = "VGhpcyBpcyBhIEJhc2U2NCB0ZXN0Lg=="; /* echo -n "This is a Base64 test." | b64encode -r - */
+
+ assert(Base64Encode((unsigned char *) base64String, strlen(base64String), &base64Text) == 0);
+ assert(strcmp(base64Text, base64EncodeCheck) == 0);
+ assert(Base64Decode(base64Text, (unsigned char **) &base64Decode, &base64DecodeLength) == 0);
+ assert(strcmp(base64String, base64Decode) == 0);
+
+ /* public/private key tests */
+ const char *pubkeyfile = "public.pem";
+ const char *privkeyfile = "private.pem";
+
+ /* built-in tests */
+ assert(test_load_pubkey_from_file(pubkeyfile) == 0);
+ assert(test_load_private_key_from_file(privkeyfile) == 0);
+
+ /* load public key pair for use in further tests */
+ EVP_PKEY *pubkey, *privkey;
+ pubkey = load_pubkey_from_file(pubkeyfile);
+ assert(pubkey);
+ privkey = load_privkey_from_file(privkeyfile);
+ assert(privkey);
+
+ /* authentication token tests */
+ assert(test_authtoken("kilroy", "fubar", pubkey, privkey) == 0);
+
+ /* This should fail because the data is way too long for the RSA key */
+ /* assert(test_authtoken("kilroykilroykilroykilroykilroykilroykilroykilroykilroykilroykilroykilroykilroykilroykilroykilroykilroykilroykilroykilroykilroykilroykilroykilroykilroykilroy", "fubarfubarfubarfubarfubarfubarfubarfubarfubarfubarfubarfubarfubarfubarfubarfubarfubarfubarfubarfubarfubarfubarfubarfubarfubarfubarfubarfubarfubarfubarfubar", pubkey, privkey) < 0); */
+
+ return 0;
+}
+
+int
+test_authtoken(const char *authUser, const char *authPassword, EVP_PKEY *pubkey, EVP_PKEY *privkey) {
+ char *authToken;
+ char *decodeUser;
+ char *decodePassword;
+ time_t decodeTime;
+
+ assert(encode_auth_setting(authUser, authPassword, pubkey, &authToken) == 0);
+ assert(decode_auth_setting(0, authToken, privkey, &decodeUser, &decodePassword, &decodeTime) == 0);
+
+ assert(strcmp(decodeUser, authUser) == 0);
+ assert(strcmp(decodePassword, authPassword) == 0);
+
+ time_t now = time(NULL);
+
+ assert(now - decodeTime >= 0); /* time has to go forwards */
+ assert(now - decodeTime <= 1); /* shouldn't take more than a second to run */
+
+ return 0;
+}
+#else
+int
+main(int argc, char **argv)
+{
+ return 0;
+}
+#endif /* HAVE_SSL */
diff --git a/src/tcp_info.c b/src/tcp_info.c
index bfbb9ea..d63e5b4 100644
--- a/src/tcp_info.c
+++ b/src/tcp_info.c
@@ -197,13 +197,13 @@ get_pmtu(struct iperf_interval_results *irp)
void
build_tcpinfo_message(struct iperf_interval_results *r, char *message)
{
-#if defined(linux)
+#if defined(linux) && defined(TCP_INFO)
sprintf(message, report_tcpInfo, r->tcpInfo.tcpi_snd_cwnd, r->tcpInfo.tcpi_snd_ssthresh,
r->tcpInfo.tcpi_rcv_ssthresh, r->tcpInfo.tcpi_unacked, r->tcpInfo.tcpi_sacked,
r->tcpInfo.tcpi_lost, r->tcpInfo.tcpi_retrans, r->tcpInfo.tcpi_fackets,
r->tcpInfo.tcpi_rtt, r->tcpInfo.tcpi_reordering);
#endif
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) && defined(TCP_INFO)
sprintf(message, report_tcpInfo, r->tcpInfo.tcpi_snd_cwnd,
r->tcpInfo.tcpi_rcv_space, r->tcpInfo.tcpi_snd_ssthresh, r->tcpInfo.tcpi_rtt);
#endif
diff --git a/src/timer.h b/src/timer.h
index 301cdf3..58c3db8 100644
--- a/src/timer.h
+++ b/src/timer.h
@@ -31,6 +31,8 @@
#define __TIMER_H
#include <time.h>
+#include <sys/time.h>
+
#include "iperf_time.h"
/* TimerClientData is an opaque value that tags along with a timer. The