Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

130 increase line buffer size #134

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ChangeLog
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
next
=====
*
* Added `japi_set_max_linebuf_size()` to enable parsing of large JSON commands

0.4.0
=====
Expand Down
9 changes: 5 additions & 4 deletions include/creadline.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@
#ifndef __CREADLINE_H__
#define __CREADLINE_H__

/*! Override the maximum line size here (default: 64 MiB) */
//#define CREADLINE_MAX_LINE_SIZE 10*1024*1024
#include <stddef.h>

/*! Define creadline's block size.
*
Expand Down Expand Up @@ -79,12 +78,13 @@ typedef struct __creadline_buffer {
* \param fd File descriptor
* \param dst Pointer to a pointer to the read line
* \param buffer creadline buffer for storing remaining characters
* \param max_linebuf_size Maximum line length to parse
*
* \returns -1 on error,
* 0 on EOF or when a zero-length line was read (check dst),
* length of the read line otherwise
*/
int creadline_r(int fd, void **dst, creadline_buf_t *buffer);
int creadline_r(int fd, void **dst, creadline_buf_t *buffer, size_t max_linebuf_size);

/*!
* \brief Read a single line from a file descriptor.
Expand All @@ -96,12 +96,13 @@ int creadline_r(int fd, void **dst, creadline_buf_t *buffer);
*
* \param fd File descriptor
* \param dst Pointer to a pointer to the read line
* \param max_linebuf_size Maximum line length to parse
*
* \returns -1 on error,
* 0 on EOF or when a zero-length line was read (check dst),
* length of the read line otherwise
*/
int creadline(int fd, void **dst);
int creadline(int fd, void **dst, size_t max_linebuf_size);

#ifdef __cplusplus
}
Expand Down
16 changes: 16 additions & 0 deletions include/japi.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ typedef struct __japi_context {
void *userptr; /*!< Pointer to user data */
uint16_t num_clients; /*!< Number of connected clients */
uint16_t max_clients; /*!< Number of maximal allowed clients */
size_t max_linebuf_size;
pthread_mutex_t lock; /*!< Mutual access lock */
struct __japi_request *requests; /*!< Pointer to the JAPI request list */
struct __japi_pushsrv_context
Expand Down Expand Up @@ -147,6 +148,21 @@ int japi_register_request(japi_context *ctx, const char *req_name,
*/
int japi_start_server(japi_context *ctx, const char *port);

/*!
* \brief Define the maximum line size a japi-command can have
*
* Change default value of 64MiB = 64*1024*1024. Some applications need more
* need more capacity to transfer data. The line parser will round down to powers of 2 times
* CREADLINE_BLOCK_SIZE (1*1024, 2*1024, 4*1024, 8*1024, ...).
*
* \param ctx JAPI context
* \param max_linebuf_size_user Maximum line length of Japi-Commands (>1024)
*
* \returns On success, zero is returned. On error, -1 for empty JAPI context and -2 on too small line length, is
* returned.
*/
int japi_set_max_linebuf_size(japi_context *ctx, size_t max_linebuf_size_user);

/*!
* \brief Set the number of allowed clients
*
Expand Down
23 changes: 6 additions & 17 deletions src/creadline.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,6 @@

#include "creadline.h"

/* Do not change the maximum line size here! Define
* CREADLINE_MAX_LINE_SIZE in the header file to
* overwrite the default value. */
#ifndef CREADLINE_MAX_LINE_SIZE
/*! Internal definition of the maximum allowed line size. Can be overwritten by
* defining CREADLINE_MAX_LINE_SIZE. */
#define __MAX_LINEBUF_SIZE__ 64*1024*1024
#else
#define __MAX_LINEBUF_SIZE__ CREADLINE_MAX_LINE_SIZE
#endif

static int strnpos(const char *s, int c, size_t maxlen)
{
int pos;
Expand All @@ -67,7 +56,7 @@ static int strnpos(const char *s, int c, size_t maxlen)
return -1;
}

int creadline_r(int fd, void **dst, creadline_buf_t *buffer)
int creadline_r(int fd, void **dst, creadline_buf_t *buffer, size_t max_linebuf_size)
{
char *linebuf;
size_t linebuf_size;
Expand Down Expand Up @@ -102,15 +91,15 @@ int creadline_r(int fd, void **dst, creadline_buf_t *buffer)

/* Check if there is enough space left to call read again. If a new
* read could write beyond the line buffer it's size is doubled as long
* as __MAX_LINEBUF_SIZE__ is not reached. */
* as max_linebuf_size is not reached. */

if (linebuf_nbytes + CREADLINE_BLOCK_SIZE > linebuf_size) {

char* new_linebuf = NULL;
int new_linebuf_size = 2*linebuf_size;

if (new_linebuf_size > __MAX_LINEBUF_SIZE__) {
fprintf(stderr, "ERROR: Maximum line size of %i bytes exceeded!\n", __MAX_LINEBUF_SIZE__);
if (new_linebuf_size > max_linebuf_size) {
fprintf(stderr, "ERROR: Maximum line size of %li bytes exceeded!\n", max_linebuf_size);
goto error_free;
}

Expand Down Expand Up @@ -191,7 +180,7 @@ int creadline_r(int fd, void **dst, creadline_buf_t *buffer)
return -1;
}

int creadline(int fd, void **dst)
int creadline(int fd, void **dst, size_t max_linebuf_size)
{
static int fd_last = -1;
static creadline_buf_t buffer;
Expand All @@ -202,6 +191,6 @@ int creadline(int fd, void **dst)
fd_last = fd;
}

return creadline_r(fd, dst, &buffer);
return creadline_r(fd, dst, &buffer, max_linebuf_size);
}

22 changes: 21 additions & 1 deletion src/japi.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
#include <stddef.h>

#include "japi.h"

Expand Down Expand Up @@ -310,6 +311,7 @@ japi_context *japi_init(void *userptr)
ctx->clients = NULL;
ctx->num_clients = 0;
ctx->max_clients = 0;
ctx->max_linebuf_size = 64 * 1024 * 1024; /* 64MiB maximum line length per default. */
ctx->include_args_in_response = false;
ctx->shutdown = false;

Expand Down Expand Up @@ -337,6 +339,24 @@ japi_context *japi_init(void *userptr)
return ctx;
}

int japi_set_max_linebuf_size(japi_context *ctx, size_t max_linebuf_size_user)
{
/* Error handling */
if (ctx == NULL) {
fprintf(stderr, "ERROR: JAPI context is NULL.\n");
return -1;
}

Michael-M-Baron marked this conversation as resolved.
Show resolved Hide resolved
if (max_linebuf_size_user < CREADLINE_BLOCK_SIZE) {
fprintf(stderr, "ERROR: Minimal linesize is CREADLINE_BLOCK_SIZE of %u bytes\n", CREADLINE_BLOCK_SIZE);
return -2;
}

ctx->max_linebuf_size = max_linebuf_size_user;

return 0;
}

/*
* Set maximal allowed number of clients.
* 0 is interpreted as unlimited number of allowed clients.
Expand Down Expand Up @@ -558,7 +578,7 @@ int japi_start_server(japi_context *ctx, const char *port)
do {

ret = creadline_r(client->socket, (void **)&request,
&(client->crl_buffer));
&(client->crl_buffer),ctx->max_linebuf_size);
if (ret > 0) {

response = NULL;
Expand Down
37 changes: 37 additions & 0 deletions test/japi_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ extern "C" {
#include "japi_pushsrv_intern.h"
#include "japi_utils.h"
#include "rw_n.h"
#include "creadline.h"
}

/* The handler for japi_register_request test */
Expand Down Expand Up @@ -183,6 +184,42 @@ TEST(JAPI, IncludeArgsWithResponse)
japi_destroy(ctx);
}

TEST(JAPI, SetMaxLinebufSize)
{
/* Setup */
japi_context *ctx = japi_init(NULL);
char *response = NULL;
const char *sval;
const char *request = "{'japi_request':'dummy_request_handler'}";
json_object *jobj;
json_object *jdata;
int socket = 4;
japi_register_request(ctx, "dummy_request_handler", &dummy_request_handler);

/* Configure context to include request arguments in response */
EXPECT_EQ(japi_set_max_linebuf_size(NULL, CREADLINE_BLOCK_SIZE), -1);

EXPECT_EQ(japi_set_max_linebuf_size(ctx, 0), -2);

/* Test valid line size */
EXPECT_EQ(japi_set_max_linebuf_size(ctx, CREADLINE_BLOCK_SIZE), 0);

/* TODO: set_max_linebuf_size is actually used by creadline_r which is
* not invoked in japi_process_message(). A mock client socket with
* dummy data has to be created so creadline can read from this socket.
* */

/* On success, 0 returned. On error, -1 is returned */
EXPECT_EQ(japi_process_message(ctx, request, &response, socket), 0);
jobj = json_tokener_parse(response);
json_object_object_get_ex(jobj, "data", &jdata);
EXPECT_EQ(japi_get_value_as_str(jdata, "value", &sval), 0);
EXPECT_STREQ("hello world", sval);

/* Clean up */
japi_destroy(ctx);
}

TEST(JAPI, Register)
{
japi_context *ctx;
Expand Down