Avoid many system calls when sending serialized data.

This commit is contained in:
Nikos Mavrogiannopoulos
2013-10-30 09:19:33 +01:00
parent 1145eafa97
commit 9e8f39faf5
7 changed files with 165 additions and 93 deletions

View File

@@ -35,6 +35,7 @@
#include <gnutls/crypto.h>
#include <tlslib.h>
#include "ipc.h"
#include "str.h"
#include <vpn.h>
#include <cookies.h>
@@ -61,23 +62,22 @@ void main_auth_init(main_server_st *s)
}
}
static int send_str_value_length(main_server_st* s, struct proc_st* proc, char* data)
static int send_value_length(main_server_st* s, struct proc_st* proc, const void* data, size_t _len)
{
uint8_t len;
uint16_t len = _len;
int ret;
if (data != NULL) {
len = strlen(data);
ret = force_write(proc->fd, &len, 1);
if (len > 0) {
ret = force_write(proc->fd, &len, 2);
if (ret < 0)
return ret;
ret = force_write(proc->fd, proc->config.ipv4_dns, len);
ret = force_write(proc->fd, data, len);
if (ret < 0)
return ret;
} else {
len = 0;
ret = force_write(proc->fd, &len, 1);
ret = force_write(proc->fd, &len, 2);
if (ret < 0)
return ret;
}
@@ -91,69 +91,75 @@ int serialize_additional_data(main_server_st* s, struct proc_st* proc)
int ret;
unsigned i;
uint8_t len;
str_st buffer;
str_init(&buffer);
/* IPv4 DNS */
if (proc->config.ipv4_dns)
mslog(s, proc, LOG_DEBUG, "sending DNS '%s'", proc->config.ipv4_dns);
ret = send_str_value_length(s, proc, proc->config.ipv4_dns);
ret = str_append_str_prefix1(&buffer, proc->config.ipv4_dns);
if (ret < 0)
return ret;
goto cleanup;
/* IPv6 DNS */
if (proc->config.ipv6_dns)
mslog(s, proc, LOG_DEBUG, "sending DNS '%s'", proc->config.ipv6_dns);
ret = send_str_value_length(s, proc, proc->config.ipv6_dns);
ret = str_append_str_prefix1(&buffer, proc->config.ipv6_dns);
if (ret < 0)
return ret;
goto cleanup;
/* IPv4 NBNS */
if (proc->config.ipv4_nbns)
mslog(s, proc, LOG_DEBUG, "sending NBNS '%s'", proc->config.ipv4_nbns);
ret = send_str_value_length(s, proc, proc->config.ipv4_nbns);
ret = str_append_str_prefix1(&buffer, proc->config.ipv4_nbns);
if (ret < 0)
return ret;
goto cleanup;
/* IPv6 NBNS */
if (proc->config.ipv6_nbns)
mslog(s, proc, LOG_DEBUG, "sending NBNS '%s'", proc->config.ipv6_nbns);
ret = send_str_value_length(s, proc, proc->config.ipv6_nbns);
ret = str_append_str_prefix1(&buffer, proc->config.ipv6_nbns);
if (ret < 0)
return ret;
goto cleanup;
/* IPv4 netmask */
if (proc->config.ipv4_netmask)
mslog(s, proc, LOG_DEBUG, "sending netmask '%s'", proc->config.ipv4_netmask);
ret = send_str_value_length(s, proc, proc->config.ipv4_netmask);
ret = str_append_str_prefix1(&buffer, proc->config.ipv4_netmask);
if (ret < 0)
return ret;
goto cleanup;
/* IPv6 netmask */
if (proc->config.ipv6_netmask)
mslog(s, proc, LOG_DEBUG, "sending netmask '%s'", proc->config.ipv6_netmask);
ret = send_str_value_length(s, proc, proc->config.ipv6_netmask);
ret = str_append_str_prefix1(&buffer, proc->config.ipv6_netmask);
if (ret < 0)
return ret;
goto cleanup;
/* routes */
len = proc->config.routes_size;
ret = force_write(proc->fd, &len, 1);
ret = str_append_data(&buffer, &len, 1);
if (ret < 0)
return ret;
goto cleanup;
for (i=0;i<proc->config.routes_size;i++) {
len = strlen(proc->config.routes[i]);
mslog(s, proc, LOG_DEBUG, "sending route '%s'", proc->config.routes[i]);
ret = force_write(proc->fd, &len, 1);
if (ret < 0)
return ret;
ret = force_write(proc->fd, proc->config.routes[i], len);
ret = str_append_str_prefix1(&buffer, proc->config.routes[i]);
if (ret < 0)
return ret;
}
ret = send_value_length(s, proc, buffer.data, buffer.length);
if (ret < 0)
goto cleanup;
return 0;
ret = 0;
cleanup:
str_clear(&buffer);
return ret;
}
int send_auth_reply(main_server_st* s, struct proc_st* proc,

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2002-2012 Free Software Foundation, Inc.
* Copyright (C) 2013 Nikos Mavrogiannopoulos
*
* Author: Nikos Mavrogiannopoulos
*
@@ -43,9 +44,9 @@ void str_clear(str_st * str)
}
#define MIN_CHUNK 64
/* This function always null terminates the string in dest.
/* This function makes sure there is an additional byte in dest;
*/
int str_append_data(str_st * dest, const void *data, size_t data_size)
int str_append_size(str_st * dest, size_t data_size)
{
size_t tot_len = data_size + dest->length;
@@ -62,9 +63,6 @@ int str_append_data(str_st * dest, const void *data, size_t data_size)
dest->data = dest->allocd;
}
memmove(&dest->data[dest->length], data, data_size);
dest->length = tot_len;
dest->data[dest->length] = 0;
return tot_len;
} else {
@@ -83,14 +81,40 @@ int str_append_data(str_st * dest, const void *data, size_t data_size)
memmove(dest->allocd, dest->data, dest->length);
dest->data = dest->allocd;
memcpy(&dest->data[dest->length], data, data_size);
dest->length = tot_len;
dest->data[dest->length] = 0;
return tot_len;
}
}
/* This function always null terminates the string in dest.
*/
int str_append_data(str_st * dest, const void *data, size_t data_size)
{
int ret;
ret = str_append_size(dest, data_size);
if (ret < 0)
return ret;
memcpy(&dest->data[dest->length], data, data_size);
dest->length = data_size + dest->length;
dest->data[dest->length] = 0;
return 0;
}
int str_append_data_prefix1(str_st * dest, const void *data, size_t data_size)
{
int ret;
uint8_t prefix = data_size;
ret = str_append_data(dest, &prefix, 1);
if (ret >= 0) {
ret = str_append_data(dest, data, data_size);
}
return ret;
}
/* Appends the provided string. The null termination byte is appended
* but not included in length.
*/
@@ -103,3 +127,44 @@ int str_append_str(str_st * dest, const char *src)
return ret;
}
/* Makes sure that the data read are null terminated (but not counted in *data_size)
* If the size of the data is zero then *data will be null;
*/
int str_read_data_prefix1(str_st * src, char **data, size_t *data_size)
{
uint8_t prefix;
if (src->length < 1)
return ERR_MEM;
prefix = src->data[0];
if (src->length < prefix)
return ERR_MEM;
src->data++;
src->length--;
if (prefix == 0) {
if (data_size)
*data_size = 0;
*data = NULL;
} else {
if (data_size)
*data_size = prefix + 1;
*data = malloc(((int)prefix)+1);
if (*data == NULL)
return ERR_MEM;
memcpy(*data, src->data, prefix);
(*data)[prefix] = 0;
src->data += prefix;
}
return 0;
}

View File

@@ -53,6 +53,10 @@ inline static void str_reset(str_st * buf)
int str_append_str(str_st *, const char *str);
int str_append_data(str_st *, const void *data, size_t data_size);
int str_append_size(str_st *, size_t data_size);
int str_append_data_prefix1(str_st *, const void *data, size_t data_size);
int str_read_data_prefix1(str_st * src, char **data, size_t *data_size);
#define str_append_str_prefix1(s, str) (((str)==NULL)?str_append_data_prefix1(s, NULL, 0):str_append_data_prefix1(s, str, strlen(str)))
#endif

View File

@@ -196,11 +196,6 @@ const char *human_addr(const struct sockaddr *sa, socklen_t salen,
#define SA_IN_SIZE(size) ((size==sizeof(struct sockaddr_in))?sizeof(struct in_addr):sizeof(struct in6_addr))
/* Helper structures */
struct route_st {
uint8_t size;
char *route;
};
enum option_types { OPTION_NUMERIC, OPTION_STRING, OPTION_BOOLEAN, OPTION_MULTI_LINE };
#endif

View File

@@ -253,28 +253,29 @@ static int send_auth_cookie_req(int fd, const struct cmd_auth_cookie_req_st* r)
return ret;
}
static int read_str_value_length(worker_st *ws, char** res)
static int recv_value_length(worker_st *ws, str_st* b)
{
int ret;
uint8_t len;
uint16_t len;
ret = force_read(ws->cmd_fd, &len, 1);
if (ret != 1) {
ret = force_read(ws->cmd_fd, &len, 2);
if (ret != 2) {
oclog(ws, LOG_ERR, "Error receiving length-value from main (%d)", ret);
return ERR_BAD_COMMAND;
}
if (len > 0) {
*res = malloc(((int)len)+1);
if (*res == NULL)
return ERR_MEM;
ret = force_read(ws->cmd_fd, *res, len);
ret = str_append_size(b, len);
if (ret < 0)
return ret;
ret = force_read(ws->cmd_fd, b->data, len);
if (ret != len) {
oclog(ws, LOG_ERR, "Error receiving value from main (%d)", ret);
return ERR_BAD_COMMAND;
}
(*res)[len] = 0;
b->length += len;
b->data[len] = 0;
}
return 0;
@@ -284,68 +285,69 @@ static
int deserialize_additional_data(worker_st* ws)
{
int ret;
uint8_t len;
unsigned i;
str_st b;
/* IPV4 DNS */
ret = read_str_value_length(ws, &ws->ipv4_dns);
str_init(&b);
ret = recv_value_length(ws, &b);
if (ret < 0)
return ret;
goto cleanup;
/* IPV4 DNS */
ret = str_read_data_prefix1(&b, &ws->ipv4_dns, NULL);
if (ret < 0)
goto cleanup;
/* IPV6 DNS */
ret = read_str_value_length(ws, &ws->ipv6_dns);
ret = str_read_data_prefix1(&b, &ws->ipv6_dns, NULL);
if (ret < 0)
return ret;
goto cleanup;
/* IPV4 NBNS */
ret = read_str_value_length(ws, &ws->ipv4_nbns);
ret = str_read_data_prefix1(&b, &ws->ipv4_nbns, NULL);
if (ret < 0)
return ret;
goto cleanup;
/* IPV6 NBNS */
ret = read_str_value_length(ws, &ws->ipv6_nbns);
ret = str_read_data_prefix1(&b, &ws->ipv6_nbns, NULL);
if (ret < 0)
return ret;
goto cleanup;
/* IPV4 netmask */
ret = read_str_value_length(ws, &ws->ipv4_netmask);
ret = str_read_data_prefix1(&b, &ws->ipv4_netmask, NULL);
if (ret < 0)
return ret;
goto cleanup;
/* IPV6 netmask */
ret = read_str_value_length(ws, &ws->ipv6_netmask);
ret = str_read_data_prefix1(&b, &ws->ipv6_netmask, NULL);
if (ret < 0)
return ret;
goto cleanup;
/* number of routes */
ret = force_read(ws->cmd_fd, &len, 1);
if (ret != 1) {
oclog(ws, LOG_ERR, "Error receiving length-value from main (%d)", ret);
return ERR_BAD_COMMAND;
if (b.length < 1) {
oclog(ws, LOG_ERR, "Error in received length-value from main");
ret = ERR_BAD_COMMAND;
goto cleanup;
}
ws->routes_size = len;
ws->routes_size = b.data[0];
b.length--;
b.data++;
/* routes */
for (i=0;i<ws->routes_size;i++) {
ret = force_read(ws->cmd_fd, &ws->routes[i].size, 1);
if (ret != 1) {
oclog(ws, LOG_ERR, "Error received route size from main (%d)", ret);
return ERR_BAD_COMMAND;
ret = str_read_data_prefix1(&b, &ws->routes[i], NULL);
if (ret < 0) {
oclog(ws, LOG_ERR, "Error receiving private routes from main");
ret = ERR_BAD_COMMAND;
goto cleanup;
}
ws->routes[i].route = malloc(ws->routes[i].size+1);
if (ws->routes[i].route == NULL)
return ERR_MEM;
ret = force_read(ws->cmd_fd, ws->routes[i].route, ws->routes[i].size);
if (ret != ws->routes[i].size) {
oclog(ws, LOG_ERR, "Error received routes from main (%d)", ret);
return ERR_BAD_COMMAND;
}
ws->routes[i].route[ws->routes[i].size] = 0;
}
return 0;
ret = 0;
cleanup:
str_clear(&b);
return ret;
}
static int recv_auth_reply(worker_st *ws, struct cmd_auth_reply_msg_st* mresp)

View File

@@ -899,13 +899,13 @@ socklen_t sl;
}
for (i=0;i<ws->routes_size;i++) {
if (req->no_ipv6 != 0 && strchr(ws->routes[i].route, ':') != 0)
if (req->no_ipv6 != 0 && strchr(ws->routes[i], ':') != 0)
continue;
if (req->no_ipv4 != 0 && strchr(ws->routes[i].route, '.') != 0)
if (req->no_ipv4 != 0 && strchr(ws->routes[i], '.') != 0)
continue;
oclog(ws, LOG_DEBUG, "adding route %s", ws->routes[i].route);
oclog(ws, LOG_DEBUG, "adding private route %s", ws->routes[i]);
ret = tls_printf(ws->session,
"X-CSTP-Split-Include: %s\r\n", ws->routes[i].route);
"X-CSTP-Split-Include: %s\r\n", ws->routes[i]);
SEND_ERR(ret);
}
ret = tls_printf(ws->session, "X-CSTP-Keepalive: %u\r\n", ws->config->keepalive);

View File

@@ -126,7 +126,7 @@ typedef struct worker_st {
char *ipv4_netmask;
char *ipv6_netmask;
unsigned routes_size;
struct route_st routes[MAX_ROUTES];
char* routes[MAX_ROUTES];
struct http_req_st req;
} worker_st;