Skip to content

Commit

Permalink
Merge pull request #98 from davidvossel/server_side_buf_limit
Browse files Browse the repository at this point in the history
Server side max buffer limit
  • Loading branch information
davidvossel committed Nov 18, 2013
2 parents b4c36ef + d17d6b3 commit b05ca12
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 11 deletions.
17 changes: 17 additions & 0 deletions include/qb/qbipcc.h
Expand Up @@ -231,6 +231,23 @@ void *qb_ipcc_context_get(qb_ipcc_connection_t *c);
*/
int32_t qb_ipcc_is_connected(qb_ipcc_connection_t *c);

/**
* What is the actual buffer size used after the connection.
*
* @note The buffer size is guaranteed to be at least the size
* of the value given in qb_ipcc_connect, but it is possible
* the server will enforce a larger size depending on the
* implementation. If the server side is known to enforce
* a buffer size, use this function after the client connection
* is established to retrieve the buffer size in use. It is
* important for the client side to know the buffer size in use
* so the client can successfully retrieve large server events.
*
* @param c connection instance
* @retval connection size in bytes or -error code
*/
int32_t qb_ipcc_get_buffer_size(qb_ipcc_connection_t * c);

/* *INDENT-OFF* */
#ifdef __cplusplus
}
Expand Down
12 changes: 12 additions & 0 deletions include/qb/qbipcs.h
Expand Up @@ -444,6 +444,18 @@ void qb_ipcs_connection_auth_set(qb_ipcs_connection_t *conn, uid_t uid,
*/
int32_t qb_ipcs_connection_get_buffer_size(qb_ipcs_connection_t *conn);

/**
* Enforce the max buffer size clients must use from the server side.
*
* @note Setting this will force client connections to use at least
* 'max_buf_size' bytes as their buffer size. If this value is not set
* on the server, the clients enforce their own buffer sizes.
*
* @param ipc server instance
* @param max buffer size in bytes
*/
void qb_ipcs_enforce_buffer_size(qb_ipcs_service_t *s, uint32_t max_buf_size);

/* *INDENT-OFF* */
#ifdef __cplusplus
}
Expand Down
1 change: 1 addition & 0 deletions lib/ipc_int.h
Expand Up @@ -133,6 +133,7 @@ struct qb_ipcs_funcs {
struct qb_ipcs_service {
enum qb_ipc_type type;
char name[NAME_MAX];
uint32_t max_buffer_size;
int32_t service_id;
int32_t ref_count;
pid_t pid;
Expand Down
6 changes: 3 additions & 3 deletions lib/ipc_setup.c
Expand Up @@ -461,9 +461,9 @@ handle_new_connection(struct qb_ipcs_service *s,
return -ENOMEM;
}
c->setup.u.us.sock = sock;
c->request.max_msg_size = req->max_msg_size;
c->response.max_msg_size = req->max_msg_size;
c->event.max_msg_size = req->max_msg_size;
c->request.max_msg_size = QB_MAX(req->max_msg_size, s->max_buffer_size);
c->response.max_msg_size = QB_MAX(req->max_msg_size, s->max_buffer_size);
c->event.max_msg_size = QB_MAX(req->max_msg_size, s->max_buffer_size);
c->pid = ugp->pid;
c->auth.uid = c->euid = ugp->uid;
c->auth.gid = c->egid = ugp->gid;
Expand Down
10 changes: 10 additions & 0 deletions lib/ipcc.c
Expand Up @@ -422,3 +422,13 @@ qb_ipcc_is_connected(qb_ipcc_connection_t *c)

return c->is_connected;
}

int32_t
qb_ipcc_get_buffer_size(qb_ipcc_connection_t * c)
{
if (c == NULL) {
return -EINVAL;
}

return c->event.max_msg_size;
}
8 changes: 8 additions & 0 deletions lib/ipcs.c
Expand Up @@ -954,3 +954,11 @@ qb_ipcs_connection_get_buffer_size(qb_ipcs_connection_t *c)
* here. */
return c->response.max_msg_size;
}

void qb_ipcs_enforce_buffer_size(qb_ipcs_service_t *s, uint32_t buf_size)
{
if (s == NULL) {
return;
}
s->max_buffer_size = buf_size;
}
41 changes: 33 additions & 8 deletions tests/check_ipc.c
Expand Up @@ -48,6 +48,7 @@ static int CALCULATED_DGRAM_MAX_MSG_SIZE = 0;
* this the largests msg we can successfully send. */
#define GIANT_MSG_DATA_SIZE MAX_MSG_SIZE - sizeof(struct qb_ipc_response_header) - 8

static int enforce_server_buffer=0;
static qb_ipcc_connection_t *conn;
static enum qb_ipc_type ipc_type;

Expand Down Expand Up @@ -372,6 +373,9 @@ run_ipc_server(void)
s1 = qb_ipcs_create(ipc_name, 4, ipc_type, &sh);
fail_if(s1 == 0);

if (enforce_server_buffer) {
qb_ipcs_enforce_buffer_size(s1, MAX_MSG_SIZE);
}
qb_ipcs_poll_handlers_set(s1, &ph);

res = qb_ipcs_run(s1);
Expand Down Expand Up @@ -431,7 +435,6 @@ send_and_check(int32_t req_id, uint32_t size,
res = qb_ipcc_send(conn, &request, MAX_MSG_SIZE*2);
ck_assert_int_eq(res, -EMSGSIZE);


repeat_send:
res = qb_ipcc_send(conn, &request, request.hdr.size);
try_times++;
Expand Down Expand Up @@ -840,7 +843,12 @@ test_ipc_bulk_events(void)
static void
test_ipc_stress_test(void)
{
struct qb_ipc_request_header req_header;
struct {
struct qb_ipc_request_header hdr __attribute__ ((aligned(8)));
char data[GIANT_MSG_DATA_SIZE] __attribute__ ((aligned(8)));
uint32_t sent_msgs __attribute__ ((aligned(8)));
} __attribute__ ((aligned(8))) giant_req;

struct qb_ipc_response_header res_header;
struct iovec iov[1];
int32_t c = 0;
Expand All @@ -849,13 +857,23 @@ test_ipc_stress_test(void)
int32_t res;
qb_loop_t *cl;
int32_t fd;

/* This looks strange, but it serves an important purpose.
* This test forces the server to enforce the MAX_MSG_SIZE
* limit from the server side, which overrides the client's
* buffer limit. To verify this functionality is working
* we set the client limit lower than what the server
* is enforcing. */
int32_t client_buf_size = MAX_MSG_SIZE - 1024;
int32_t real_buf_size;

enforce_server_buffer = 1;
pid = run_function_in_new_process(run_ipc_server);
enforce_server_buffer = 0;
fail_if(pid == -1);
sleep(1);

do {
conn = qb_ipcc_connect(ipc_name, MAX_MSG_SIZE);
conn = qb_ipcc_connect(ipc_name, client_buf_size);
if (conn == NULL) {
j = waitpid(pid, NULL, WNOHANG);
ck_assert_int_eq(j, 0);
Expand All @@ -865,6 +883,9 @@ test_ipc_stress_test(void)
} while (conn == NULL && c < 5);
fail_if(conn == NULL);

real_buf_size = qb_ipcc_get_buffer_size(conn);
ck_assert_int_eq(real_buf_size, MAX_MSG_SIZE);

qb_log(LOG_DEBUG, "Testing %d iterations of EVENT msg passing.", num_stress_events);

events_received = 0;
Expand All @@ -881,11 +902,15 @@ test_ipc_stress_test(void)
qb_loop_run(cl);
ck_assert_int_eq(events_received, num_stress_events);

req_header.id = IPC_MSG_REQ_SERVER_FAIL;
req_header.size = sizeof(struct qb_ipc_request_header);
giant_req.hdr.id = IPC_MSG_REQ_SERVER_FAIL;
giant_req.hdr.size = sizeof(giant_req);

iov[0].iov_len = req_header.size;
iov[0].iov_base = &req_header;
if (giant_req.hdr.size <= client_buf_size) {
ck_assert_int_eq(1, 0);
}

iov[0].iov_len = giant_req.hdr.size;
iov[0].iov_base = &giant_req;
res = qb_ipcc_sendv_recv(conn, iov, 1,
&res_header,
sizeof(struct qb_ipc_response_header), -1);
Expand Down

0 comments on commit b05ca12

Please sign in to comment.