aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2018-02-28 17:33:35 -0800
committerGarrett D'Amore <garrett@damore.org>2018-03-02 08:47:33 -0800
commit91089a2a60d2a74334fc67757fd23ee1f3ae56d5 (patch)
tree75abfed0b81ab63a1281c097fccee74d7857b6c9 /tools
parent04e5a756ba25f79036aa5e03e7412ed5e5539a12 (diff)
downloadnng-91089a2a60d2a74334fc67757fd23ee1f3ae56d5.tar.gz
nng-91089a2a60d2a74334fc67757fd23ee1f3ae56d5.tar.bz2
nng-91089a2a60d2a74334fc67757fd23ee1f3ae56d5.zip
fixes #247 nngcat needs TLS options
While here we also fixed a bug in the --file handling that we noticed while writing the TLS handling. We also fixed a warning in the core (msgqueue) for set but unused variables.
Diffstat (limited to 'tools')
-rw-r--r--tools/nngcat/nngcat.c232
1 files changed, 173 insertions, 59 deletions
diff --git a/tools/nngcat/nngcat.c b/tools/nngcat/nngcat.c
index 728f0c3f..04afe919 100644
--- a/tools/nngcat/nngcat.c
+++ b/tools/nngcat/nngcat.c
@@ -41,9 +41,15 @@ nng_duration sendtimeo = NNG_DURATION_INFINITE;
nng_duration recvtimeo = NNG_DURATION_INFINITE;
void * data = NULL;
size_t datalen = 0;
-size_t datacap = 0;
int compat = 0;
int async = 0;
+int insecure = 0;
+void * cacert = NULL;
+size_t cacertlen = 0;
+void * keyfile = NULL;
+size_t keylen = 0;
+void * certfile = NULL;
+size_t certlen = 0;
// Options, must start at 1 because zero is sentinel.
enum options {
@@ -85,6 +91,10 @@ enum options {
OPT_DIAL_IPC,
OPT_LISTEN_LOCAL,
OPT_DIAL_LOCAL,
+ OPT_INSECURE,
+ OPT_CACERT,
+ OPT_KEYFILE,
+ OPT_CERTFILE,
};
static nng_optspec opts[] = {
@@ -159,6 +169,15 @@ static nng_optspec opts[] = {
.o_val = OPT_DIAL_LOCAL,
.o_arg = true,
},
+ { .o_name = "insecure", .o_short = 'k', .o_val = OPT_INSECURE },
+ { .o_name = "cacert", .o_val = OPT_CACERT, .o_arg = true },
+ { .o_name = "key", .o_val = OPT_KEYFILE, .o_arg = true },
+ {
+ .o_name = "cert",
+ .o_short = 'E',
+ .o_val = OPT_CERTFILE,
+ .o_arg = true,
+ },
// Sentinel.
{ .o_name = NULL, .o_val = 0 },
@@ -243,6 +262,70 @@ intarg(const char *val, int maxv)
return (v);
}
+// This reads a file into memory. Care is taken to ensure that
+// the buffer is one byte larger and contains a terminating
+// NUL. (Useful for key files and such.)
+static void
+loadfile(const char *path, void **datap, size_t *lenp)
+{
+ FILE * f;
+ size_t cap;
+ char * data;
+ size_t len;
+ if ((f = fopen(path, "r")) == NULL) {
+ fatal("Cannot open file %s: %s", path, strerror(errno));
+ }
+ cap = 4096;
+ len = 0;
+ if ((data = malloc(cap)) == NULL) {
+ fatal("Out of memory.");
+ }
+ data[0] = '\0';
+ for (;;) {
+ size_t n;
+ // Read until end of file, reallocating as needed.
+ if (len == (cap - 1)) {
+ void *old = data;
+ cap *= 2;
+ if ((data = realloc(old, cap)) == NULL) {
+ fatal("Out of memory");
+ }
+ }
+ n = fread(data + len, 1, cap - len, f);
+ if (n == 0) {
+ if (ferror(f)) {
+ fatal("Read file %s failed: %s", path,
+ strerror(errno));
+ }
+ break;
+ }
+ len += n;
+ data[len] = '\0';
+ }
+ fclose(f);
+ *datap = data;
+ *lenp = len;
+}
+
+static void
+configtls(nng_tls_config *tls)
+{
+ int rv = 0;
+ if (insecure) {
+ rv = nng_tls_config_auth_mode(tls, NNG_TLS_AUTH_MODE_NONE);
+ }
+ if ((rv == 0) && (certfile != NULL)) {
+ keyfile = keyfile ? keyfile : certfile;
+ rv = nng_tls_config_own_cert(tls, certfile, keyfile, NULL);
+ }
+ if ((rv == 0) && (cacert != NULL)) {
+ rv = nng_tls_config_ca_chain(tls, cacert, NULL);
+ }
+ if (rv != 0) {
+ fatal("Unable to configure TLS: %s", nng_strerror(rv));
+ }
+}
+
struct addr {
struct addr *next;
int mode;
@@ -335,7 +418,8 @@ printmsg(char *buf, size_t len)
putchar('"');
putchar('\n');
break;
- case OPT_MSGPACK: // MsgPack, we just encode prefix + len, then raw.
+ case OPT_MSGPACK: // MsgPack, we just encode prefix + len, then
+ // raw.
if (len < 256) {
putchar('\xc4');
putchar(len & 0xff);
@@ -352,7 +436,8 @@ printmsg(char *buf, size_t len)
}
fwrite(buf, 1, len, stdout);
break;
- case OPT_HEX: // Hex, quoted C string encoded with hex literals.
+ case OPT_HEX: // Hex, quoted C string encoded with hex
+ // literals.
putchar('"');
for (size_t i = 0; i < len; i++) {
printf("\\x%02x", (uint8_t) buf[i]);
@@ -375,8 +460,8 @@ recvloop(nng_socket sock)
switch (rv) {
case NNG_ETIMEDOUT:
case NNG_ESTATE:
- // Either a regular timeout, or we reached the end
- // of an event like a survey completing.
+ // Either a regular timeout, or we reached the
+ // end of an event like a survey completing.
return;
case 0:
printmsg(nng_msg_body(msg), nng_msg_len(msg));
@@ -443,9 +528,9 @@ sendloop(nng_socket sock)
break;
}
// We sleep, but we account for time spent, so that our
- // interval appears more or less constant. Of course if we
- // took more than the interval here, then we skip the sleep
- // altogether.
+ // interval appears more or less constant. Of course
+ // if we took more than the interval here, then we skip
+ // the sleep altogether.
if ((delta >= 0) && (delta < interval)) {
nng_msleep(interval - delta);
}
@@ -490,8 +575,9 @@ sendrecv(nng_socket sock)
break;
}
- // We would like to use recvloop, but we need to reset our
- // timeout each time, as the timer counts down towards zero.
+ // We would like to use recvloop, but we need to reset
+ // our timeout each time, as the timer counts down
+ // towards zero.
for (;;) {
delta = (nng_duration)(nng_clock() - start);
@@ -529,9 +615,9 @@ sendrecv(nng_socket sock)
delta = (nng_duration)(end - start);
// We sleep, but we account for time spent, so that our
- // interval appears more or less constant. Of course if we
- // took more than the interval here, then we skip the sleep
- // altogether.
+ // interval appears more or less constant. Of course
+ // if we took more than the interval here, then we skip
+ // the sleep altogether.
if ((delta >= 0) && (delta < interval)) {
nng_msleep(interval - delta);
}
@@ -552,7 +638,6 @@ main(int ac, const char **av)
struct topic **topicend;
nng_socket sock;
int port;
- FILE * f;
idx = 1;
addrend = &addrs;
@@ -655,56 +740,49 @@ main(int ac, const char **av)
break;
case OPT_FILE:
if (data != NULL) {
- fatal("Data (--file, --data) may be specified "
+ fatal("Data (--file, --data) may be "
+ "specified "
"only once.");
}
- if ((f = fopen(arg, "r")) == NULL) {
- fatal("Cannot open file %s: %s", arg,
- strerror(errno));
- }
- for (;;) {
- size_t n;
- // Read until end of file, reallocating as
- // needed.
- if (datacap == 0) {
- data = malloc(4096);
- datacap = 4096;
- } else if (datacap == datalen) {
- void *odata = data;
- datacap *= 2;
- data = realloc(odata, datacap);
- if (data == NULL) {
- free(odata);
- }
- }
- if (data == NULL) {
- fatal("Out of memory.");
- }
- n = fread((char *) data + datalen, 1,
- datacap - datalen, f);
- if (n == 0) {
- if (ferror(f)) {
- fatal(
- "Read file %s failed: %s",
- arg, strerror(errno));
- }
- break;
- }
- }
- fclose(f);
+ loadfile(arg, &data, &datalen);
break;
case OPT_DATA:
if (data != NULL) {
- fatal("Data (--file, --data) may be specified "
+ fatal("Data (--file, --data) may be "
+ "specified "
"only once.");
}
if ((data = malloc(strlen(arg) + 1)) == NULL) {
fatal("Out of memory.");
}
memcpy(data, arg, strlen(arg) + 1);
- datacap = strlen(arg) + 1;
datalen = strlen(arg);
break;
+ case OPT_CACERT:
+ if (cacert != NULL) {
+ fatal("CA Certificate (--cacert) may be "
+ "specified only once.");
+ }
+ loadfile(arg, &cacert, &cacertlen);
+ break;
+ case OPT_KEYFILE:
+ if (keyfile != NULL) {
+ fatal(
+ "Key (--key) may be specified only once.");
+ }
+ loadfile(arg, &keyfile, &keylen);
+ break;
+ case OPT_CERTFILE:
+ if (certfile != NULL) {
+ fatal("Cert (--cert) may be specified "
+ "only "
+ "once.");
+ }
+ loadfile(arg, &certfile, &certlen);
+ break;
+ case OPT_INSECURE:
+ insecure = 1;
+ break;
}
}
switch (rv) {
@@ -725,7 +803,8 @@ main(int ac, const char **av)
if (compat) {
if (async != 0) {
- fatal("Option --async and --compat are incompatible.");
+ fatal("Option --async and --compat are "
+ "incompatible.");
}
if (proto == OPT_PAIR) {
proto = OPT_PAIR0;
@@ -761,8 +840,17 @@ main(int ac, const char **av)
}
break;
case OPT_PUSH0:
- case OPT_SURVEY0:
case OPT_PUB0:
+ if (format != 0) {
+ fatal("Protocol does not support --format "
+ "options.");
+ }
+ if (data == NULL) {
+ fatal("Protocol requires either --file or "
+ "--data.");
+ }
+ break;
+ case OPT_SURVEY0:
case OPT_REQ0:
if (data == NULL) {
fatal("Protocol requires either --file or "
@@ -890,22 +978,48 @@ main(int ac, const char **av)
fatal("Unable to set send timeout: %s", nng_strerror(rv));
}
- // XXX: TBD: This is where we should add other socket options,
- // like TLS configuration, timeouts, etc.
-
for (struct addr *a = addrs; a != NULL; a = a->next) {
- char *act;
+ char * act;
+ nng_listener l;
+ nng_dialer d;
+ nng_tls_config *tls;
switch (a->mode) {
case OPT_DIAL:
case OPT_DIAL_IPC:
case OPT_DIAL_LOCAL:
- rv = nng_dial(sock, a->val, NULL, async);
+ rv = nng_dialer_create(&d, sock, a->val);
+ if (rv != 0) {
+ fatal("Unable to create dialer for %s: %s",
+ a->val, nng_strerror(rv));
+ }
+ rv = nng_dialer_getopt_ptr(
+ d, NNG_OPT_TLS_CONFIG, (void **) &tls);
+ if (rv == 0) {
+ configtls(tls);
+ } else if (rv != NNG_ENOTSUP) {
+ fatal("Unable to get TLS config: %s",
+ nng_strerror(rv));
+ }
+ rv = nng_dialer_start(d, async);
act = "dial";
break;
case OPT_LISTEN:
case OPT_LISTEN_IPC:
case OPT_LISTEN_LOCAL:
- rv = nng_listen(sock, a->val, NULL, async);
+ rv = nng_listener_create(&l, sock, a->val);
+ if (rv != 0) {
+ fatal("Unable to create listener for %s: %s",
+ a->val, nng_strerror(rv));
+ }
+ rv = nng_listener_getopt_ptr(
+ l, NNG_OPT_TLS_CONFIG, (void **) &tls);
+ if (rv == 0) {
+ configtls(tls);
+ } else if (rv != NNG_ENOTSUP) {
+ fatal("Unable to get TLS config: %s",
+ nng_strerror(rv));
+ }
+ rv = nng_listener_start(l, async);
act = "listen";
break;
default: