1
1

(Mostly) switched error reporting to a single routine that handles JSON mode.

Этот коммит содержится в:
Jef Poskanzer 2013-02-07 12:35:17 -08:00
родитель cda2ce2a7e
Коммит b5e0751f59
8 изменённых файлов: 184 добавлений и 158 удалений

Просмотреть файл

@ -14,7 +14,6 @@
#include <errno.h> #include <errno.h>
#include <signal.h> #include <signal.h>
#include <unistd.h> #include <unistd.h>
#include <stdarg.h>
#include <assert.h> #include <assert.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/socket.h> #include <sys/socket.h>
@ -1387,7 +1386,7 @@ iperf_print_intermediate(struct iperf_test *test)
/* sum up all streams */ /* sum up all streams */
irp = TAILQ_LAST(&sp->result->interval_results, irlisthead); irp = TAILQ_LAST(&sp->result->interval_results, irlisthead);
if (irp == NULL) { if (irp == NULL) {
fprintf(stderr, "iperf_print_intermediate Error: interval_results is NULL\n"); iperf_err(test, "iperf_print_intermediate error: interval_results is NULL");
return; return;
} }
bytes += irp->bytes_transferred; bytes += irp->bytes_transferred;
@ -1395,7 +1394,7 @@ iperf_print_intermediate(struct iperf_test *test)
retransmits += irp->this_retrans; retransmits += irp->this_retrans;
} }
if (bytes <=0) { /* this can happen if timer goes off just when client exits */ if (bytes <=0) { /* this can happen if timer goes off just when client exits */
fprintf(stderr, "error: bytes <= 0!\n"); iperf_err(test, "error: bytes <= 0!");
return; return;
} }
/* next build string with sum of all streams */ /* next build string with sum of all streams */
@ -1613,7 +1612,7 @@ print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON *
irp = TAILQ_LAST(&sp->result->interval_results, irlisthead); /* get last entry in linked list */ irp = TAILQ_LAST(&sp->result->interval_results, irlisthead); /* get last entry in linked list */
if (irp == NULL) { if (irp == NULL) {
fprintf(stderr, "print_interval_results Error: interval_results is NULL \n"); iperf_err(test, "print_interval_results error: interval_results is NULL");
return; return;
} }
if (!test->json_output) { if (!test->json_output) {
@ -1826,80 +1825,3 @@ iperf_json_finish(struct iperf_test *test)
test->json_top = test->json_start = test->json_intervals = test->json_end = NULL; test->json_top = test->json_start = test->json_intervals = test->json_end = NULL;
return 0; return 0;
} }
/* Helper routine for building cJSON objects in a printf-like manner.
**
** Sample call:
** j = iperf_json_printf("foo: %b bar: %d bletch: %f eep: %s", b, i, f, s);
**
** The four formatting characters and the types they expect are:
** %b boolean int
** %d integer int64_t
** %f floating point double
** %s string char *
** If the values you're passing in are not these exact types, you must
** cast them, there is no automatic type coercion/widening here.
**
** The colons mark the end of field names, and blanks are ignored.
**
** This routine is not particularly robust, but it's not part of the API,
** it's just for internal iperf3 use.
**
** It currently lives in iperf_api.c, rather than iperf_util.c, because
** putting it in iperf_util.c would mean adding -lm to more executables,
** because the cJSON package uses libm/floor(). If I get around to fixing
** that, then this routine can move.
*/
cJSON*
iperf_json_printf(const char *format, ...)
{
cJSON* o;
va_list argp;
const char *cp;
char name[100];
char* np;
cJSON* j;
o = cJSON_CreateObject();
if (o == NULL)
return NULL;
va_start(argp, format);
np = name;
for (cp = format; *cp != '\0'; ++cp) {
switch (*cp) {
case ' ':
break;
case ':':
*np = '\0';
break;
case '%':
++cp;
switch (*cp) {
case 'b':
j = cJSON_CreateBool(va_arg(argp, int));
break;
case 'd':
j = cJSON_CreateInt(va_arg(argp, int64_t));
break;
case 'f':
j = cJSON_CreateFloat(va_arg(argp, double));
break;
case 's':
j = cJSON_CreateString(va_arg(argp, char *));
break;
default:
return NULL;
}
if (j == NULL)
return NULL;
cJSON_AddItemToObject(o, name, j);
np = name;
break;
default:
*np++ = *cp;
break;
}
}
va_end(argp);
return o;
}

Просмотреть файл

@ -195,10 +195,10 @@ void iperf_test_reset(struct iperf_test *);
/* JSON output routines. */ /* JSON output routines. */
int iperf_json_start(struct iperf_test *); int iperf_json_start(struct iperf_test *);
int iperf_json_finish(struct iperf_test *); int iperf_json_finish(struct iperf_test *);
cJSON* iperf_json_printf(const char *format, ...);
/* Error routines. */ /* Error routines. */
void iperf_error(char *); void iperf_err(struct iperf_test *test, const char *format, ...) __attribute__ ((format(printf,2,3)));
void iperf_errexit(struct iperf_test *test, const char *format, ...) __attribute__ ((format(printf,2,3),noreturn));
char *iperf_strerror(int); char *iperf_strerror(int);
extern int i_errno; extern int i_errno;
enum { enum {

Просмотреть файл

@ -11,9 +11,47 @@
#include <errno.h> #include <errno.h>
#include <netdb.h> #include <netdb.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include "iperf.h" #include "iperf.h"
#include "iperf_api.h" #include "iperf_api.h"
static void
iperf_verr(struct iperf_test *test, const char *format, va_list argp)
{
char str[1000];
vsnprintf(str, sizeof(str), format, argp);
if (test != NULL && test->json_output && test->json_top != NULL) {
cJSON_AddStringToObject(test->json_top, "error", str);
iperf_json_finish(test);
} else
fprintf(stderr, "iperf3: %s\n", str);
}
/* Do a printf to stderr. */
void
iperf_err(struct iperf_test *test, const char *format, ...)
{
va_list argp;
va_start(argp, format);
iperf_verr(test, format, argp);
va_end(argp);
}
/* Do a printf to stderr, then exit. */
void
iperf_errexit(struct iperf_test *test, const char *format, ...)
{
va_list argp;
va_start(argp, format);
iperf_verr(test, format, argp);
va_end(argp);
exit(1);
}
int i_errno; int i_errno;
char * char *
@ -28,198 +66,198 @@ iperf_strerror(int i_errno)
switch (i_errno) { switch (i_errno) {
case IENONE: case IENONE:
snprintf(errstr, len, "No error"); snprintf(errstr, len, "no error");
break; break;
case IESERVCLIENT: case IESERVCLIENT:
snprintf(errstr, len, "Iperf cannot be both server and client"); snprintf(errstr, len, "cannot be both server and client");
break; break;
case IENOROLE: case IENOROLE:
snprintf(errstr, len, "Iperf instance must either be a client (-c) or server (-s)"); snprintf(errstr, len, "must either be a client (-c) or server (-s)");
break; break;
case IECLIENTONLY: case IECLIENTONLY:
snprintf(errstr, len, "Some option you are trying to set is client only"); snprintf(errstr, len, "some option you are trying to set is client only");
break; break;
case IEDURATION: case IEDURATION:
snprintf(errstr, len, "Test duration too long (maximum = %d seconds)", MAX_TIME); snprintf(errstr, len, "test duration too long (maximum = %d seconds)", MAX_TIME);
break; break;
case IENUMSTREAMS: case IENUMSTREAMS:
snprintf(errstr, len, "Number of parallel streams too large (maximum = %d)", MAX_STREAMS); snprintf(errstr, len, "number of parallel streams too large (maximum = %d)", MAX_STREAMS);
break; break;
case IEBLOCKSIZE: case IEBLOCKSIZE:
snprintf(errstr, len, "Block size too large (maximum = %d bytes)", MAX_BLOCKSIZE); snprintf(errstr, len, "block size too large (maximum = %d bytes)", MAX_BLOCKSIZE);
break; break;
case IEBUFSIZE: case IEBUFSIZE:
snprintf(errstr, len, "Socket buffer size too large (maximum = %d bytes)", MAX_TCP_BUFFER); snprintf(errstr, len, "socket buffer size too large (maximum = %d bytes)", MAX_TCP_BUFFER);
break; break;
case IEINTERVAL: case IEINTERVAL:
snprintf(errstr, len, "Report interval too large (maximum = %d seconds)", MAX_INTERVAL); snprintf(errstr, len, "report interval too large (maximum = %d seconds)", MAX_INTERVAL);
break; break;
case IEMSS: case IEMSS:
snprintf(errstr, len, "TCP MSS too large (maximum = %d bytes)", MAX_MSS); snprintf(errstr, len, "TCP MSS too large (maximum = %d bytes)", MAX_MSS);
break; break;
case IENEWTEST: case IENEWTEST:
snprintf(errstr, len, "Unable to create a new test"); snprintf(errstr, len, "unable to create a new test");
perr = 1; perr = 1;
break; break;
case IEINITTEST: case IEINITTEST:
snprintf(errstr, len, "Test initialization failed"); snprintf(errstr, len, "test initialization failed");
perr = 1; perr = 1;
break; break;
case IELISTEN: case IELISTEN:
snprintf(errstr, len, "Unable to start listener for connections"); snprintf(errstr, len, "unable to start listener for connections");
perr = 1; perr = 1;
break; break;
case IECONNECT: case IECONNECT:
snprintf(errstr, len, "Unable to connect to server"); snprintf(errstr, len, "unable to connect to server");
herr = 1; herr = 1;
perr = 1; perr = 1;
break; break;
case IEACCEPT: case IEACCEPT:
snprintf(errstr, len, "Unable to accept connection from client"); snprintf(errstr, len, "unable to accept connection from client");
herr = 1; herr = 1;
perr = 1; perr = 1;
break; break;
case IESENDCOOKIE: case IESENDCOOKIE:
snprintf(errstr, len, "Unable to send cookie to server"); snprintf(errstr, len, "unable to send cookie to server");
perr = 1; perr = 1;
break; break;
case IERECVCOOKIE: case IERECVCOOKIE:
snprintf(errstr, len, "Unable to receive cookie to server"); snprintf(errstr, len, "unable to receive cookie to server");
perr = 1; perr = 1;
break; break;
case IECTRLWRITE: case IECTRLWRITE:
snprintf(errstr, len, "Unable to write to the control socket"); snprintf(errstr, len, "unable to write to the control socket");
perr = 1; perr = 1;
break; break;
case IECTRLREAD: case IECTRLREAD:
snprintf(errstr, len, "Unable to read from the control socket"); snprintf(errstr, len, "unable to read from the control socket");
perr = 1; perr = 1;
break; break;
case IECTRLCLOSE: case IECTRLCLOSE:
snprintf(errstr, len, "Control socket has closed unexpectedly"); snprintf(errstr, len, "control socket has closed unexpectedly");
break; break;
case IEMESSAGE: case IEMESSAGE:
snprintf(errstr, len, "Received an unknown control message"); snprintf(errstr, len, "received an unknown control message");
break; break;
case IESENDMESSAGE: case IESENDMESSAGE:
snprintf(errstr, len, "Unable to send control message"); snprintf(errstr, len, "unable to send control message");
perr = 1; perr = 1;
break; break;
case IERECVMESSAGE: case IERECVMESSAGE:
snprintf(errstr, len, "Unable to receive control message"); snprintf(errstr, len, "unable to receive control message");
perr = 1; perr = 1;
break; break;
case IESENDPARAMS: case IESENDPARAMS:
snprintf(errstr, len, "Unable to send parameters to server"); snprintf(errstr, len, "unable to send parameters to server");
perr = 1; perr = 1;
break; break;
case IERECVPARAMS: case IERECVPARAMS:
snprintf(errstr, len, "Unable to receive parameters from client"); snprintf(errstr, len, "unable to receive parameters from client");
perr = 1; perr = 1;
break; break;
case IEPACKAGERESULTS: case IEPACKAGERESULTS:
snprintf(errstr, len, "Unable to package results"); snprintf(errstr, len, "unable to package results");
perr = 1; perr = 1;
break; break;
case IESENDRESULTS: case IESENDRESULTS:
snprintf(errstr, len, "Unable to send results"); snprintf(errstr, len, "unable to send results");
perr = 1; perr = 1;
break; break;
case IERECVRESULTS: case IERECVRESULTS:
snprintf(errstr, len, "Unable to receive results"); snprintf(errstr, len, "unable to receive results");
perr = 1; perr = 1;
break; break;
case IESELECT: case IESELECT:
snprintf(errstr, len, "Select failed"); snprintf(errstr, len, "select failed");
perr = 1; perr = 1;
break; break;
case IECLIENTTERM: case IECLIENTTERM:
snprintf(errstr, len, "The client has terminated"); snprintf(errstr, len, "the client has terminated");
break; break;
case IESERVERTERM: case IESERVERTERM:
snprintf(errstr, len, "The server has terminated"); snprintf(errstr, len, "the server has terminated");
break; break;
case IEACCESSDENIED: case IEACCESSDENIED:
snprintf(errstr, len, "The server is busy running a test. try again later"); snprintf(errstr, len, "the server is busy running a test. try again later");
break; break;
case IESETNODELAY: case IESETNODELAY:
snprintf(errstr, len, "Unable to set TCP NODELAY"); snprintf(errstr, len, "unable to set TCP NODELAY");
perr = 1; perr = 1;
break; break;
case IESETMSS: case IESETMSS:
snprintf(errstr, len, "Unable to set TCP MSS"); snprintf(errstr, len, "unable to set TCP MSS");
perr = 1; perr = 1;
break; break;
case IESETBUF: case IESETBUF:
snprintf(errstr, len, "Unable to set socket buffer size"); snprintf(errstr, len, "unable to set socket buffer size");
perr = 1; perr = 1;
break; break;
case IESETTOS: case IESETTOS:
snprintf(errstr, len, "Unable to set IP TOS"); snprintf(errstr, len, "unable to set IP TOS");
perr = 1; perr = 1;
break; break;
case IESETCOS: case IESETCOS:
snprintf(errstr, len, "Unable to set IPv6 traffic class"); snprintf(errstr, len, "unable to set IPv6 traffic class");
perr = 1; perr = 1;
break; break;
case IEREUSEADDR: case IEREUSEADDR:
snprintf(errstr, len, "Unable to reuse address on socket"); snprintf(errstr, len, "unable to reuse address on socket");
perr = 1; perr = 1;
break; break;
case IENONBLOCKING: case IENONBLOCKING:
snprintf(errstr, len, "Unable to set socket to non-blocking"); snprintf(errstr, len, "unable to set socket to non-blocking");
perr = 1; perr = 1;
break; break;
case IESETWINDOWSIZE: case IESETWINDOWSIZE:
snprintf(errstr, len, "Unable to set socket window size"); snprintf(errstr, len, "unable to set socket window size");
perr = 1; perr = 1;
break; break;
case IEPROTOCOL: case IEPROTOCOL:
snprintf(errstr, len, "Protocol does not exist"); snprintf(errstr, len, "protocol does not exist");
break; break;
case IECREATESTREAM: case IECREATESTREAM:
snprintf(errstr, len, "Unable to create a new stream"); snprintf(errstr, len, "unable to create a new stream");
herr = 1; herr = 1;
perr = 1; perr = 1;
break; break;
case IEINITSTREAM: case IEINITSTREAM:
snprintf(errstr, len, "Unable to initialize stream"); snprintf(errstr, len, "unable to initialize stream");
herr = 1; herr = 1;
perr = 1; perr = 1;
break; break;
case IESTREAMLISTEN: case IESTREAMLISTEN:
snprintf(errstr, len, "Unable to start stream listener"); snprintf(errstr, len, "unable to start stream listener");
perr = 1; perr = 1;
break; break;
case IESTREAMCONNECT: case IESTREAMCONNECT:
snprintf(errstr, len, "Unable to connect stream"); snprintf(errstr, len, "unable to connect stream");
herr = 1; herr = 1;
perr = 1; perr = 1;
break; break;
case IESTREAMACCEPT: case IESTREAMACCEPT:
snprintf(errstr, len, "Unable to accept stream connection"); snprintf(errstr, len, "unable to accept stream connection");
perr = 1; perr = 1;
break; break;
case IESTREAMWRITE: case IESTREAMWRITE:
snprintf(errstr, len, "Unable to write to stream socket"); snprintf(errstr, len, "unable to write to stream socket");
perr = 1; perr = 1;
break; break;
case IESTREAMREAD: case IESTREAMREAD:
snprintf(errstr, len, "Unable to read from stream socket"); snprintf(errstr, len, "unable to read from stream socket");
perr = 1; perr = 1;
break; break;
case IESTREAMCLOSE: case IESTREAMCLOSE:
snprintf(errstr, len, "Stream socket has closed unexpectedly"); snprintf(errstr, len, "stream socket has closed unexpectedly");
break; break;
case IESTREAMID: case IESTREAMID:
snprintf(errstr, len, "Stream has an invalid id"); snprintf(errstr, len, "stream has an invalid id");
break; break;
case IENEWTIMER: case IENEWTIMER:
snprintf(errstr, len, "Unable to create new timer"); snprintf(errstr, len, "unable to create new timer");
perr = 1; perr = 1;
break; break;
case IEUPDATETIMER: case IEUPDATETIMER:
snprintf(errstr, len, "Unable to update timer"); snprintf(errstr, len, "unable to update timer");
perr = 1; perr = 1;
break; break;
} }
@ -234,9 +272,3 @@ iperf_strerror(int i_errno)
return errstr; return errstr;
} }
void
iperf_error(char *estr)
{
fprintf(stderr, "%s: %s\n", estr, iperf_strerror(i_errno));
}

Просмотреть файл

@ -159,7 +159,7 @@ iperf_handle_message_server(struct iperf_test *test)
// XXX: Need to rethink how this behaves to fit API // XXX: Need to rethink how this behaves to fit API
if ((rval = Nread(test->ctrl_sck, &test->state, sizeof(char), Ptcp)) <= 0) { if ((rval = Nread(test->ctrl_sck, &test->state, sizeof(char), Ptcp)) <= 0) {
if (rval == 0) { if (rval == 0) {
fprintf(stderr, "The client has unexpectedly closed the connection.\n"); iperf_err(test, "the client has unexpectedly closed the connection");
i_errno = IECTRLCLOSE; i_errno = IECTRLCLOSE;
test->state = IPERF_DONE; test->state = IPERF_DONE;
return 0; return 0;
@ -202,7 +202,7 @@ iperf_handle_message_server(struct iperf_test *test)
i_errno = IECLIENTTERM; i_errno = IECLIENTTERM;
// XXX: Remove this line below! // XXX: Remove this line below!
fprintf(stderr, "The client has terminated.\n"); iperf_err(test, "the client has terminated");
SLIST_FOREACH(sp, &test->streams, streams) { SLIST_FOREACH(sp, &test->streams, streams) {
FD_CLR(sp->socket, &test->read_set); FD_CLR(sp->socket, &test->read_set);
FD_CLR(sp->socket, &test->write_set); FD_CLR(sp->socket, &test->write_set);

Просмотреть файл

@ -67,7 +67,7 @@ iperf_udp_recv(struct iperf_stream *sp)
sp->packet_count = pcount; sp->packet_count = pcount;
} else { } else {
sp->outoforder_packets++; sp->outoforder_packets++;
fprintf(stderr, "OUT OF ORDER - incoming packet = %d and received packet = %d AND SP = %d\n", pcount, sp->packet_count, sp->socket); iperf_err(sp->test, "OUT OF ORDER - incoming packet = %d and received packet = %d AND SP = %d", pcount, sp->packet_count, sp->socket);
} }
/* jitter measurement */ /* jitter measurement */

Просмотреть файл

@ -17,6 +17,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <stdarg.h>
#include <sys/select.h> #include <sys/select.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/time.h> #include <sys/time.h>
@ -24,6 +25,7 @@
#include <errno.h> #include <errno.h>
#include "config.h" #include "config.h"
#include "cjson.h"
/* make_cookie /* make_cookie
* *
@ -177,3 +179,75 @@ cpu_util(double *pcpu)
*pcpu = ((ctemp - clast) / timediff) * 100; *pcpu = ((ctemp - clast) / timediff) * 100;
} }
/* Helper routine for building cJSON objects in a printf-like manner.
**
** Sample call:
** j = iperf_json_printf("foo: %b bar: %d bletch: %f eep: %s", b, i, f, s);
**
** The four formatting characters and the types they expect are:
** %b boolean int
** %d integer int64_t
** %f floating point double
** %s string char *
** If the values you're passing in are not these exact types, you must
** cast them, there is no automatic type coercion/widening here.
**
** The colons mark the end of field names, and blanks are ignored.
**
** This routine is not particularly robust, but it's not part of the API,
** it's just for internal iperf3 use.
*/
cJSON*
iperf_json_printf(const char *format, ...)
{
cJSON* o;
va_list argp;
const char *cp;
char name[100];
char* np;
cJSON* j;
o = cJSON_CreateObject();
if (o == NULL)
return NULL;
va_start(argp, format);
np = name;
for (cp = format; *cp != '\0'; ++cp) {
switch (*cp) {
case ' ':
break;
case ':':
*np = '\0';
break;
case '%':
++cp;
switch (*cp) {
case 'b':
j = cJSON_CreateBool(va_arg(argp, int));
break;
case 'd':
j = cJSON_CreateInt(va_arg(argp, int64_t));
break;
case 'f':
j = cJSON_CreateFloat(va_arg(argp, double));
break;
case 's':
j = cJSON_CreateString(va_arg(argp, char *));
break;
default:
return NULL;
}
if (j == NULL)
return NULL;
cJSON_AddItemToObject(o, name, j);
np = name;
break;
default:
*np++ = *cp;
break;
}
}
va_end(argp);
return o;
}

Просмотреть файл

@ -10,6 +10,8 @@
#ifndef __IPERF_UTIL_H #ifndef __IPERF_UTIL_H
#define __IPERF_UTIL_H #define __IPERF_UTIL_H
#include "cjson.h"
void make_cookie(char *); void make_cookie(char *);
int is_closed(int); int is_closed(int);
@ -24,4 +26,6 @@ int delay(int64_t ns);
void cpu_util(double *); void cpu_util(double *);
cJSON* iperf_json_printf(const char *format, ...);
#endif #endif

Просмотреть файл

@ -74,10 +74,8 @@ main(int argc, char **argv)
#endif #endif
test = iperf_new_test(); test = iperf_new_test();
if (!test) { if (!test)
iperf_error("create new test error"); iperf_errexit(NULL, "create new test error - %s", iperf_strerror(i_errno));
exit(1);
}
iperf_defaults(test); /* sets defaults */ iperf_defaults(test); /* sets defaults */
// XXX: Check signal for errors? // XXX: Check signal for errors?
@ -94,16 +92,14 @@ main(int argc, char **argv)
} }
if (iperf_parse_arguments(test, argc, argv) < 0) { if (iperf_parse_arguments(test, argc, argv) < 0) {
iperf_error("parameter error"); iperf_err(test, "parameter error - %s", iperf_strerror(i_errno));
fprintf(stderr, "\n"); fprintf(stderr, "\n");
usage_long(); usage_long();
exit(1); exit(1);
} }
if (iperf_run(test) < 0) { if (iperf_run(test) < 0)
iperf_error("error"); iperf_errexit(test, "error - %s", iperf_strerror(i_errno));
exit(1);
}
iperf_free_test(test); iperf_free_test(test);
@ -144,17 +140,15 @@ iperf_run(struct iperf_test * test)
case 's': case 's':
for (;;) { for (;;) {
if (iperf_run_server(test) < 0) { if (iperf_run_server(test) < 0) {
iperf_error("error"); iperf_err(test, "error - %s", iperf_strerror(i_errno));
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
iperf_reset_test(test); iperf_reset_test(test);
} }
break; break;
case 'c': case 'c':
if (iperf_run_client(test) < 0) { if (iperf_run_client(test) < 0)
iperf_error("error"); iperf_errexit(test, "error - %s", iperf_strerror(i_errno));
exit(1);
}
break; break;
default: default:
usage(); usage();