blob: 1b3ff96b31c5fd25dfd3dc2384b0943fc08704ec [file] [log] [blame]
Radek Krejci8fd1f5e2012-07-24 17:33:36 +02001/*!
2 * \file test-client.c
3 * \brief Testing client sending JSON requsts to the mod_netconf socket
4 * \author Radek Krejci <rkrejci@cesnet.cz>
5 * \date 2012
6 */
7/*
8 * Copyright (C) 2012 CESNET
9 *
10 * LICENSE TERMS
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in
19 * the documentation and/or other materials provided with the
20 * distribution.
21 * 3. Neither the name of the Company nor the names of its contributors
22 * may be used to endorse or promote products derived from this
23 * software without specific prior written permission.
24 *
25 * ALTERNATIVELY, provided that this notice is retained in full, this
26 * product may be distributed under the terms of the GNU General Public
27 * License (GPL) version 2 or later, in which case the provisions
28 * of the GPL apply INSTEAD OF those given above.
29 *
30 * This software is provided ``as is'', and any express or implied
31 * warranties, including, but not limited to, the implied warranties of
32 * merchantability and fitness for a particular purpose are disclaimed.
33 * In no event shall the company or contributors be liable for any
34 * direct, indirect, incidental, special, exemplary, or consequential
35 * damages (including, but not limited to, procurement of substitute
36 * goods or services; loss of use, data, or profits; or business
37 * interruption) however caused and on any theory of liability, whether
38 * in contract, strict liability, or tort (including negligence or
39 * otherwise) arising in any way out of the use of this software, even
40 * if advised of the possibility of such damage.
41 *
42 */
43
David Kupka1e3e4c82012-09-04 09:32:15 +020044#define _GNU_SOURCE
Radek Krejci8fd1f5e2012-07-24 17:33:36 +020045#include <unistd.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49#include <errno.h>
50#include <sys/types.h>
51#include <sys/socket.h>
52#include <sys/un.h>
53#include <json/json.h>
David Kupka1e3e4c82012-09-04 09:32:15 +020054#include <ctype.h>
Radek Krejci8fd1f5e2012-07-24 17:33:36 +020055
Radek Krejci6cb08982012-07-25 18:01:06 +020056#define SOCKET_FILENAME "/tmp/mod_netconf.sock"
David Kupka1e3e4c82012-09-04 09:32:15 +020057#define BUFFER_SIZE 40960
Radek Krejci8fd1f5e2012-07-24 17:33:36 +020058
59typedef enum MSG_TYPE {
60 REPLY_OK,
61 REPLY_DATA,
62 REPLY_ERROR,
Radek Krejci9e04c7b2012-07-26 15:54:25 +020063 REPLY_INFO,
Radek Krejci8fd1f5e2012-07-24 17:33:36 +020064 MSG_CONNECT,
65 MSG_DISCONNECT,
66 MSG_GET,
67 MSG_GETCONFIG,
68 MSG_EDITCONFIG,
69 MSG_COPYCONFIG,
70 MSG_DELETECONFIG,
71 MSG_LOCK,
72 MSG_UNLOCK,
Radek Krejci9e04c7b2012-07-26 15:54:25 +020073 MSG_KILL,
Radek Krejci80c10d92012-07-30 08:38:50 +020074 MSG_INFO,
75 MSG_GENERIC
Radek Krejci8fd1f5e2012-07-24 17:33:36 +020076} MSG_TYPE;
77
78void print_help(char* progname)
79{
80 printf("Usage: %s <command>\n", progname);
81 printf("Available commands:\n");
82 printf("\tconnect\n");
83 printf("\tdisconnect\n");
84 printf("\tcopy-config\n");
85 printf("\tdelete-config\n");
86 printf("\tedit-config\n");
87 printf("\tget\n");
88 printf("\tget-config\n");
89 printf("\tkill-session\n");
90 printf("\tlock\n");
91 printf("\tunlock\n");
Radek Krejci9e04c7b2012-07-26 15:54:25 +020092 printf("\tinfo\n");
Radek Krejci80c10d92012-07-30 08:38:50 +020093 printf("\tgeneric\n");
Radek Krejci8fd1f5e2012-07-24 17:33:36 +020094}
95
96int main (int argc, char* argv[])
97{
Kupka David00b9c5c2012-09-05 09:45:50 +020098 json_object* msg = NULL, *reply = NULL, *capabilities = NULL;
Radek Krejci8fd1f5e2012-07-24 17:33:36 +020099 const char* msg_text;
100 int sock;
101 struct sockaddr_un addr;
102 size_t len;
David Kupka1e3e4c82012-09-04 09:32:15 +0200103 char *buffer;
104 char* line = NULL, *chunked_msg_text;
Radek Krejci9e04c7b2012-07-26 15:54:25 +0200105 int i, alen;
David Kupka1e3e4c82012-09-04 09:32:15 +0200106 int buffer_size, buffer_len, ret, chunk_len;
107 char c, chunk_len_str[12];
Radek Krejci8fd1f5e2012-07-24 17:33:36 +0200108
109 if (argc != 2) {
110 print_help(argv[0]);
111 return (2);
112 }
113
114 /* connect to the daemon */
115 sock = socket(PF_UNIX, SOCK_STREAM, 0);
116 if (sock == -1) {
117 fprintf(stderr, "Creating socket failed (%s)", strerror(errno));
118 return (EXIT_FAILURE);
119 }
120 addr.sun_family = AF_UNIX;
121 strncpy(addr.sun_path, SOCKET_FILENAME, sizeof(addr.sun_path));
122 len = strlen(addr.sun_path) + sizeof(addr.sun_family);
123 if (connect(sock, (struct sockaddr *) &addr, len) == -1) {
124 fprintf(stderr, "Connecting to mod_netconf (%s) failed (%s)", SOCKET_FILENAME, strerror(errno));
125 close(sock);
126 return (EXIT_FAILURE);
127 }
128
129 line = malloc(sizeof(char) * BUFFER_SIZE);
130
131 if (strcmp(argv[1], "connect") == 0) {
Radek Krejciaa422df2012-07-25 18:04:59 +0200132 /*
133 * create NETCONF session
134 */
Radek Krejci8fd1f5e2012-07-24 17:33:36 +0200135 msg = json_object_new_object();
136 json_object_object_add(msg, "type", json_object_new_int(MSG_CONNECT));
137 printf("Hostname: ");
138 getline (&line, &len, stdin);
139 line[(strlen(line)-1)] = 0;
140 json_object_object_add(msg, "host", json_object_new_string(line));
141 printf("Port: ");
142 getline (&line, &len, stdin);
143 line[(strlen(line)-1)] = 0;
144 json_object_object_add(msg, "port", json_object_new_string(line));
145 printf("Username: ");
146 getline (&line, &len, stdin);
147 line[(strlen(line)-1)] = 0;
148 json_object_object_add(msg, "user", json_object_new_string(line));
149 printf("Password: ");
150 system("stty -echo");
151 getline (&line, &len, stdin);
152 system("stty echo");
153 printf("\n");
154 line[(strlen(line)-1)] = 0;
155 json_object_object_add(msg, "pass", json_object_new_string(line));
Kupka David00b9c5c2012-09-05 09:45:50 +0200156 printf("Supported capabilities\n");
157 capabilities = json_object_new_array();
158 json_object_object_add(msg, "capabilities", capabilities);
159 while (1) {
160 printf("Next capability (empty for end): ");
161 getline (&line, &len, stdin);
162 if (line == NULL || strcmp(line,"\n") == 0) {
163 break;
164 }
165 line[(strlen(line)-1)] = 0;
166 json_object_array_add (capabilities, json_object_new_string(line));
167 }
Radek Krejci8fd1f5e2012-07-24 17:33:36 +0200168 } else if (strcmp(argv[1], "disconnect") == 0) {
Radek Krejciaa422df2012-07-25 18:04:59 +0200169 /*
170 * Close NETCONF session
171 */
Radek Krejci8fd1f5e2012-07-24 17:33:36 +0200172 msg = json_object_new_object();
173 json_object_object_add(msg, "type", json_object_new_int(MSG_DISCONNECT));
174 printf("Session: ");
175 getline (&line, &len, stdin);
176 line[(strlen(line)-1)] = 0;
177 json_object_object_add(msg, "session", json_object_new_string(line));
178 } else if (strcmp(argv[1], "copy-config") == 0) {
Radek Krejciaa422df2012-07-25 18:04:59 +0200179 /*
180 * NETCONF <copy-config>
181 */
Radek Krejci035bf4e2012-07-25 10:59:09 +0200182 msg = json_object_new_object();
183 json_object_object_add(msg, "type", json_object_new_int(MSG_COPYCONFIG));
184 printf("Session: ");
185 getline (&line, &len, stdin);
186 line[(strlen(line)-1)] = 0;
187 json_object_object_add(msg, "session", json_object_new_string(line));
188 printf("Source (running|startup|candidate): ");
189 getline (&line, &len, stdin);
190 line[(strlen(line)-1)] = 0;
Radek Krejciae021c12012-07-25 18:03:52 +0200191 if (strlen(line) > 0) {
192 json_object_object_add(msg, "source", json_object_new_string(line));
193 } else {
Tomas Cejkae3721972012-08-23 13:15:29 +0200194 printf("Configuration data (ending with CTRL+D): ");
195 getdelim (&line, &len, 'D' - 0x40, stdin);
Radek Krejciae021c12012-07-25 18:03:52 +0200196 line[(strlen(line)-1)] = 0;
197 json_object_object_add(msg, "config", json_object_new_string(line));
198 }
Radek Krejci035bf4e2012-07-25 10:59:09 +0200199 printf("Target (running|startup|candidate): ");
200 getline (&line, &len, stdin);
201 line[(strlen(line)-1)] = 0;
202 json_object_object_add(msg, "target", json_object_new_string(line));
Radek Krejci8fd1f5e2012-07-24 17:33:36 +0200203 } else if (strcmp(argv[1], "delete-config") == 0) {
Radek Krejciaa422df2012-07-25 18:04:59 +0200204 /*
205 * NETCONF <delete-config>
206 */
207 msg = json_object_new_object();
208 json_object_object_add(msg, "type", json_object_new_int(MSG_DELETECONFIG));
209 printf("Session: ");
210 getline (&line, &len, stdin);
211 line[(strlen(line)-1)] = 0;
212 json_object_object_add(msg, "session", json_object_new_string(line));
213 printf("Target (running|startup|candidate): ");
214 getline (&line, &len, stdin);
215 line[(strlen(line)-1)] = 0;
216 json_object_object_add(msg, "target", json_object_new_string(line));
Radek Krejci8fd1f5e2012-07-24 17:33:36 +0200217 } else if (strcmp(argv[1], "edit-config") == 0) {
Radek Krejciaa422df2012-07-25 18:04:59 +0200218 /*
219 * NETCONF <edit-config>
220 */
221 msg = json_object_new_object();
222 json_object_object_add(msg, "type", json_object_new_int(MSG_EDITCONFIG));
223 printf("Session: ");
224 getline (&line, &len, stdin);
225 line[(strlen(line)-1)] = 0;
226 json_object_object_add(msg, "session", json_object_new_string(line));
227 printf("Target (running|startup|candidate): ");
228 getline(&line, &len, stdin);
229 line[(strlen(line) - 1)] = 0;
230 json_object_object_add(msg, "target", json_object_new_string(line));
231 printf("Default operation (merge|replace|none): ");
232 getline(&line, &len, stdin);
233 line[(strlen(line) - 1)] = 0;
234 if (strlen(line) > 0) {
235 json_object_object_add(msg, "default-operation", json_object_new_string(line));
236 }
237 printf("Error option (stop-on-error|continue-on-error|rollback-on-error): ");
238 getline(&line, &len, stdin);
239 line[(strlen(line) - 1)] = 0;
240 if (strlen(line) > 0) {
241 json_object_object_add(msg, "error-option", json_object_new_string(line));
242 }
Tomas Cejkae3721972012-08-23 13:15:29 +0200243 printf("Configuration data (ending with CTRL+D): ");
244 getdelim(&line, &len, 'D' - 0x40, stdin);
Radek Krejciaa422df2012-07-25 18:04:59 +0200245 line[(strlen(line) - 1)] = 0;
Radek Krejcib1e08f42012-07-26 10:54:28 +0200246 json_object_object_add(msg, "config", json_object_new_string(line));
Radek Krejci8fd1f5e2012-07-24 17:33:36 +0200247 } else if (strcmp(argv[1], "get") == 0) {
Radek Krejciaa422df2012-07-25 18:04:59 +0200248 /*
249 * NETCONF <get>
250 */
Radek Krejci8fd1f5e2012-07-24 17:33:36 +0200251 msg = json_object_new_object();
252 json_object_object_add(msg, "type", json_object_new_int(MSG_GET));
253 printf("Session: ");
254 getline (&line, &len, stdin);
255 line[(strlen(line)-1)] = 0;
256 json_object_object_add(msg, "session", json_object_new_string(line));
257 printf("Filter: ");
258 getline(&line, &len, stdin);
259 line[(strlen(line)-1)] = 0;
260 if (strlen(line) > 0) {
261 json_object_object_add(msg, "filter", json_object_new_string(line));
262 }
263 } else if (strcmp(argv[1], "get-config") == 0) {
Radek Krejciaa422df2012-07-25 18:04:59 +0200264 /*
265 * NETCONF <get-config>
266 */
Radek Krejci8fd1f5e2012-07-24 17:33:36 +0200267 msg = json_object_new_object();
268 json_object_object_add(msg, "type", json_object_new_int(MSG_GETCONFIG));
269 printf("Session: ");
270 getline (&line, &len, stdin);
271 line[(strlen(line)-1)] = 0;
272 json_object_object_add(msg, "session", json_object_new_string(line));
273 printf("Source (running|startup|candidate): ");
274 getline (&line, &len, stdin);
275 line[(strlen(line)-1)] = 0;
276 json_object_object_add(msg, "source", json_object_new_string(line));
277 printf("Filter: ");
278 getline(&line, &len, stdin);
279 line[(strlen(line)-1)] = 0;
280 if (strlen(line) > 0) {
281 json_object_object_add(msg, "filter", json_object_new_string(line));
282 }
283 } else if (strcmp(argv[1], "kill-session") == 0) {
Radek Krejciaa422df2012-07-25 18:04:59 +0200284 /*
285 * NETCONF <kill-session>
286 */
287 msg = json_object_new_object();
288 json_object_object_add(msg, "type", json_object_new_int(MSG_KILL));
289 printf("Session: ");
290 getline (&line, &len, stdin);
291 line[(strlen(line)-1)] = 0;
292 json_object_object_add(msg, "session", json_object_new_string(line));
293 printf("Kill session with ID: ");
294 getline (&line, &len, stdin);
295 line[(strlen(line)-1)] = 0;
296 json_object_object_add(msg, "session-id", json_object_new_string(line));
Radek Krejci8fd1f5e2012-07-24 17:33:36 +0200297 } else if (strcmp(argv[1], "lock") == 0) {
Radek Krejciaa422df2012-07-25 18:04:59 +0200298 /*
299 * NETCONF <lock>
300 */
301 msg = json_object_new_object();
302 json_object_object_add(msg, "type", json_object_new_int(MSG_LOCK));
303 printf("Session: ");
304 getline (&line, &len, stdin);
305 line[(strlen(line)-1)] = 0;
306 json_object_object_add(msg, "session", json_object_new_string(line));
307 printf("Target (running|startup|candidate): ");
308 getline (&line, &len, stdin);
309 line[(strlen(line)-1)] = 0;
310 json_object_object_add(msg, "target", json_object_new_string(line));
Radek Krejci8fd1f5e2012-07-24 17:33:36 +0200311 } else if (strcmp(argv[1], "unlock") == 0) {
Radek Krejciaa422df2012-07-25 18:04:59 +0200312 /*
313 * NETCONF <unlock>
314 */
315 msg = json_object_new_object();
316 json_object_object_add(msg, "type", json_object_new_int(MSG_UNLOCK));
317 printf("Session: ");
318 getline (&line, &len, stdin);
319 line[(strlen(line)-1)] = 0;
320 json_object_object_add(msg, "session", json_object_new_string(line));
321 printf("Target (running|startup|candidate): ");
322 getline (&line, &len, stdin);
323 line[(strlen(line)-1)] = 0;
324 json_object_object_add(msg, "target", json_object_new_string(line));
Radek Krejci9e04c7b2012-07-26 15:54:25 +0200325 } else if (strcmp(argv[1], "info") == 0) {
326 /*
327 * Get information about NETCONF session
328 */
329 msg = json_object_new_object();
330 json_object_object_add(msg, "type", json_object_new_int(MSG_INFO));
331 printf("Session: ");
332 getline (&line, &len, stdin);
333 line[(strlen(line)-1)] = 0;
334 json_object_object_add(msg, "session", json_object_new_string(line));
Radek Krejci80c10d92012-07-30 08:38:50 +0200335 } else if (strcmp(argv[1], "generic") == 0) {
336 /*
337 * Generic NETCONF request
338 */
339 msg = json_object_new_object();
340 json_object_object_add(msg, "type", json_object_new_int(MSG_GENERIC));
341 printf("Session: ");
342 getline (&line, &len, stdin);
343 line[(strlen(line)-1)] = 0;
344 json_object_object_add(msg, "session", json_object_new_string(line));
345 printf("NETCONF <rpc> content: ");
346 getline(&line, &len, stdin);
347 line[(strlen(line) - 1)] = 0;
348 json_object_object_add(msg, "content", json_object_new_string(line));
Radek Krejci8fd1f5e2012-07-24 17:33:36 +0200349 } else {
Radek Krejciaa422df2012-07-25 18:04:59 +0200350 /*
351 * Unknown request
352 */
Radek Krejci8fd1f5e2012-07-24 17:33:36 +0200353 fprintf(stderr, "Unknown command %s\n", argv[1]);
354 close(sock);
355 return (EXIT_FAILURE);
356 }
357
358 /* send the message */
359 if (msg != NULL) {
360 msg_text = json_object_to_json_string(msg);
David Kupka1e3e4c82012-09-04 09:32:15 +0200361 asprintf (&chunked_msg_text, "\n#%d\n%s\n##\n", (int)strlen(msg_text), msg_text);
Radek Krejci8fd1f5e2012-07-24 17:33:36 +0200362
Radek Krejci035bf4e2012-07-25 10:59:09 +0200363 if (json_object_object_get(msg, "pass") == NULL) {
364 /* print message only if it does not contain password */
365 printf("Sending: %s\n", msg_text);
366 }
David Kupka1e3e4c82012-09-04 09:32:15 +0200367 send(sock, chunked_msg_text, strlen(chunked_msg_text) + 1, 0);
Radek Krejci8fd1f5e2012-07-24 17:33:36 +0200368
369 json_object_put(msg);
David Kupka1e3e4c82012-09-04 09:32:15 +0200370 free (chunked_msg_text);
Radek Krejci8fd1f5e2012-07-24 17:33:36 +0200371 } else {
372 close(sock);
373 return (EXIT_FAILURE);
374 }
375
David Kupka1e3e4c82012-09-04 09:32:15 +0200376 /* read json in chunked framing */
377 buffer_size = 0;
378 buffer_len = 0;
379 buffer = NULL;
380 while (1) {
381 /* read chunk length */
382 if ((ret = recv (sock, &c, 1, 0)) != 1 || c != '\n') {
383 free (buffer);
384 buffer = NULL;
385 break;
386 }
387 if ((ret = recv (sock, &c, 1, 0)) != 1 || c != '#') {
388 free (buffer);
389 buffer = NULL;
390 break;
391 }
392 i=0;
393 memset (chunk_len_str, 0, 12);
394 while ((ret = recv (sock, &c, 1, 0) == 1 && (isdigit(c) || c == '#'))) {
395 if (i==0 && c == '#') {
396 if (recv (sock, &c, 1, 0) != 1 || c != '\n') {
397 /* end but invalid */
398 free (buffer);
399 buffer = NULL;
400 }
401 /* end of message, double-loop break */
402 goto msg_complete;
403 }
404 chunk_len_str[i++] = c;
405 }
406 if (c != '\n') {
407 free (buffer);
408 buffer = NULL;
409 break;
410 }
411 if ((chunk_len = atoi (chunk_len_str)) == 0) {
412 free (buffer);
413 buffer = NULL;
414 break;
415 }
416 buffer_size += chunk_len+1;
417 buffer = realloc (buffer, sizeof(char)*buffer_size);
418 if ((ret = recv (sock, buffer+buffer_len, chunk_len, 0)) == -1 || ret != chunk_len) {
419 free (buffer);
420 buffer = NULL;
421 break;
422 }
423 buffer_len += ret;
Radek Krejci8fd1f5e2012-07-24 17:33:36 +0200424 }
David Kupka1e3e4c82012-09-04 09:32:15 +0200425msg_complete:
426
427 if (buffer != NULL) {
428 reply = json_tokener_parse(buffer);
429 free (buffer);
430 } else {
431 reply = NULL;
432 }
433
Radek Krejci035bf4e2012-07-25 10:59:09 +0200434 printf("Received:\n");
435 if (reply == NULL) {
436 printf("(null)\n");
437 } else {
438 json_object_object_foreach(reply, key, value) {
439 printf("Key: %s, Value: ", key);
440 switch (json_object_get_type(value)) {
441 case json_type_string:
442 printf("%s\n", json_object_get_string(value));
443 break;
444 case json_type_int:
445 printf("%d\n", json_object_get_int(value));
446 break;
Radek Krejci9e04c7b2012-07-26 15:54:25 +0200447 case json_type_array:
448 printf("\n");
449 alen = json_object_array_length(value);
450 for (i = 0; i < alen; i++) {
451 printf("\t(%d) %s\n", i, json_object_get_string(json_object_array_get_idx(value, i)));
452 }
453 break;
Radek Krejci035bf4e2012-07-25 10:59:09 +0200454 default:
455 printf("\n");
456 break;
457 }
458 }
459 json_object_put(reply);
460 }
Radek Krejci8fd1f5e2012-07-24 17:33:36 +0200461 close(sock);
462 free(line);
463
464 return (EXIT_SUCCESS);
465}