mod_netconf, test-client: JSON messages are now encoded using Chunked Framing Mechanism before sending over UNIX socket.
diff --git a/src/README b/src/README
index 08ea6b4..dceacbc 100644
--- a/src/README
+++ b/src/README
@@ -20,8 +20,10 @@
--------------------------
UNIX socket (with default path /tmp/mod_netconf.sock) is used for communication
-with mod_netconf daemon. Messages are formated using JSON with the following
-content. Client is free to send multiple requests when the communication socket
+with mod_netconf daemon. Messages are formated using JSON and encoded using
+Chunked Framing Mechanism described in RFC6242 (http://tools.ietf.org/html/rfc6242#section-4.2)
+with the following content.
+Client is free to send multiple requests when the communication socket
to the mod_netconf daemon is opened.
Replies
diff --git a/src/mod_netconf.c b/src/mod_netconf.c
index ceff507..c9cfecd 100644
--- a/src/mod_netconf.c
+++ b/src/mod_netconf.c
@@ -767,27 +767,51 @@
buffer_len = 0;
buffer = NULL;
while (1) {
- fds.fd = client;
- fds.events = POLLIN;
- fds.revents = 0;
-
- status = poll(&fds, 1, 1000);
-
- if (status == 0 || (status == -1 && (errno == EAGAIN || (errno == EINTR && isterminated == 0)))) {
- /* poll was interrupted - check if the isterminated is set and if not, try poll again */
- //ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "poll interrupted");
- continue;
- } else if (status < 0) {
- /* 0: poll time outed
- * close socket and ignore this request from the client, it can try it again
- * -1: poll failed
- * something wrong happend, close this socket and wait for another request
- */
- //ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "poll failed, status %d(%d: %s)", status, errno, strerror(errno));
- close(client);
+ /* read chunk length */
+ if ((ret = recv (client, &c, 1, 0)) != 1 || c != '\n') {
+ free (buffer);
+ buffer = NULL;
break;
}
- /* status > 0 */
+ if ((ret = recv (client, &c, 1, 0)) != 1 || c != '#') {
+ free (buffer);
+ buffer = NULL;
+ break;
+ }
+ i=0;
+ memset (chunk_len_str, 0, 12);
+ while ((ret = recv (client, &c, 1, 0) == 1 && (isdigit(c) || c == '#'))) {
+ if (i==0 && c == '#') {
+ if (recv (client, &c, 1, 0) != 1 || c != '\n') {
+ /* end but invalid */
+ free (buffer);
+ buffer = NULL;
+ }
+ /* end of message, double-loop break */
+ goto msg_complete;
+ }
+ chunk_len_str[i++] = c;
+ }
+ if (c != '\n') {
+ free (buffer);
+ buffer = NULL;
+ break;
+ }
+ if ((chunk_len = atoi (chunk_len_str)) == 0) {
+ free (buffer);
+ buffer = NULL;
+ break;
+ }
+ buffer_size += chunk_len+1;
+ buffer = realloc (buffer, sizeof(char)*buffer_size);
+ if ((ret = recv (client, buffer+buffer_len, chunk_len, 0)) == -1 || ret != chunk_len) {
+ free (buffer);
+ buffer = NULL;
+ break;
+ }
+ buffer_len += ret;
+ }
+msg_complete:
if (buffer != NULL) {
request = json_tokener_parse(buffer);
@@ -1172,14 +1196,19 @@
}
json_object_put(request);
- /* send reply to caller */
- if (reply != NULL) {
- msgtext = json_object_to_json_string(reply);
- send(client, msgtext, strlen(msgtext) + 1, 0);
- json_object_put(reply);
- } else {
+ /* send reply to caller */
+ if (reply != NULL) {
+ msgtext = json_object_to_json_string(reply);
+ if (asprintf (&chunked_msg, "\n#%d\n%s\n##\n", (int)strlen(msgtext), msgtext) == -1) {
+ free (buffer);
break;
}
+ send(client, chunked_msg, strlen(chunked_msg) + 1, 0);
+ json_object_put(reply);
+ free (chunked_msg);
+ free (buffer);
+ } else {
+ break;
}
}
}
diff --git a/src/test-client.c b/src/test-client.c
index 5ae3501..0c3fa75 100644
--- a/src/test-client.c
+++ b/src/test-client.c
@@ -41,6 +41,7 @@
*
*/
+#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
@@ -50,9 +51,10 @@
#include <sys/socket.h>
#include <sys/un.h>
#include <json/json.h>
+#include <ctype.h>
#define SOCKET_FILENAME "/tmp/mod_netconf.sock"
-#define BUFFER_SIZE 4096
+#define BUFFER_SIZE 40960
typedef enum MSG_TYPE {
REPLY_OK,
@@ -98,9 +100,11 @@
int sock;
struct sockaddr_un addr;
size_t len;
- char buffer[BUFFER_SIZE];
- char* line = NULL;
+ char *buffer;
+ char* line = NULL, *chunked_msg_text;
int i, alen;
+ int buffer_size, buffer_len, ret, chunk_len;
+ char c, chunk_len_str[12];
if (argc != 2) {
print_help(argv[0]);
@@ -342,23 +346,79 @@
/* send the message */
if (msg != NULL) {
msg_text = json_object_to_json_string(msg);
+ asprintf (&chunked_msg_text, "\n#%d\n%s\n##\n", (int)strlen(msg_text), msg_text);
if (json_object_object_get(msg, "pass") == NULL) {
/* print message only if it does not contain password */
printf("Sending: %s\n", msg_text);
}
- send(sock, msg_text, strlen(msg_text) + 1, 0);
+ send(sock, chunked_msg_text, strlen(chunked_msg_text) + 1, 0);
json_object_put(msg);
+ free (chunked_msg_text);
} else {
close(sock);
return (EXIT_FAILURE);
}
- len = recv(sock, buffer, BUFFER_SIZE, 0);
- if (len > 0) {
- reply = json_tokener_parse(buffer);
+ /* read json in chunked framing */
+ buffer_size = 0;
+ buffer_len = 0;
+ buffer = NULL;
+ while (1) {
+ /* read chunk length */
+ if ((ret = recv (sock, &c, 1, 0)) != 1 || c != '\n') {
+ free (buffer);
+ buffer = NULL;
+ break;
+ }
+ if ((ret = recv (sock, &c, 1, 0)) != 1 || c != '#') {
+ free (buffer);
+ buffer = NULL;
+ break;
+ }
+ i=0;
+ memset (chunk_len_str, 0, 12);
+ while ((ret = recv (sock, &c, 1, 0) == 1 && (isdigit(c) || c == '#'))) {
+ if (i==0 && c == '#') {
+ if (recv (sock, &c, 1, 0) != 1 || c != '\n') {
+ /* end but invalid */
+ free (buffer);
+ buffer = NULL;
+ }
+ /* end of message, double-loop break */
+ goto msg_complete;
+ }
+ chunk_len_str[i++] = c;
+ }
+ if (c != '\n') {
+ free (buffer);
+ buffer = NULL;
+ break;
+ }
+ if ((chunk_len = atoi (chunk_len_str)) == 0) {
+ free (buffer);
+ buffer = NULL;
+ break;
+ }
+ buffer_size += chunk_len+1;
+ buffer = realloc (buffer, sizeof(char)*buffer_size);
+ if ((ret = recv (sock, buffer+buffer_len, chunk_len, 0)) == -1 || ret != chunk_len) {
+ free (buffer);
+ buffer = NULL;
+ break;
+ }
+ buffer_len += ret;
}
+msg_complete:
+
+ if (buffer != NULL) {
+ reply = json_tokener_parse(buffer);
+ free (buffer);
+ } else {
+ reply = NULL;
+ }
+
printf("Received:\n");
if (reply == NULL) {
printf("(null)\n");