add tests
authorMazet Laurent <laurent.mazet@thalesgroup.com>
Thu, 5 Jun 2025 14:03:36 +0000 (16:03 +0200)
committerMazet Laurent <laurent.mazet@thalesgroup.com>
Thu, 5 Jun 2025 14:03:36 +0000 (16:03 +0200)
mapec_test.c
mapec_valid.c [deleted file]
script-error.mapec [new file with mode: 0644]
udp_valid.c [new file with mode: 0644]
ulvpn.c

index f59be33df1490f8aa60dc4afa3bf9bf2aad3757d..e44bf474276500a4317ef0a2171c8a539d603189 100644 (file)
@@ -84,7 +84,7 @@ void *client (UNUSED void *dummy)
         unsigned char rx_data[32768];
 
         do {
-            rx_len = MAPEC_Receive (fid, rx_data, sizeof (rx_data));
+            rx_len = MAPEC_Receive_timeout (fid, rx_data, sizeof (rx_data), 100);
             if (rx_len == 0) {
                 VERBOSE (mapec, DEBUG, PRINTF ("client's sleeping...\n"));
                 usleep (1e3);
diff --git a/mapec_valid.c b/mapec_valid.c
deleted file mode 100644 (file)
index 25837dd..0000000
+++ /dev/null
@@ -1,504 +0,0 @@
-/*
-  File name        : mapec_valid.c
-  Projet           : MERLIN
-  Date of creation : 2025/05/23
-  Version          : 1.0
-  Copyright        : Thales SIX
-  Author           : Laurent Mazet <laurent.mazet@thalesgroup.com>
-
-  Description      : Minimal API for Packet Exchange Commmunication validation
-                     program
-
-  History          :
-  - initial version
-*/
-
-/* depend: */
-/* cflags: */
-/* linker: mapec.o */
-
-#include <errno.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "mapec.h"
-#include "verbose.h"
-
-char *progname = NULL;
-
-int stop = 0;
-
-#define BUFMAX 4096
-
-#define MAXPAYLOAD 1500
-
-void sig_handler (int sig)
-{
-    switch (sig) {
-    case SIGINT:
-        //stop = 1;
-        exit (0);
-        break;
-    case SIGTERM:
-        exit (0);
-        break;
-    }
-}
-
-#define TEST_CHARS(str, delim, stop)                      \
-    while (*str != '\0') {                                \
-        int i, stat = 0;                                  \
-        for (i = 0; (delim[i] != '\0') && (!stat); i++) { \
-            if (*str == delim[i]) {                       \
-                stat = 1;                                 \
-            }                                             \
-        }                                                 \
-        if (stat == stop) {                               \
-            break;                                        \
-        }                                                 \
-        str++;                                            \
-    }
-
-int parse_array (char *str, uint8_t *buffer, int maxlen)
-{
-    int len = 0;
-    int slen = strlen (str);
-
-    /* string payload: "..." (space must be protected by '\') */
-    if ((*str == '"') && (slen > 1)) {
-        VERBOSE (mapec, TRACE, PRINTF ("string payload: \"...\"\n"));
-        if (maxlen < slen - 2) slen = maxlen + 2;
-        if (str[slen - 1] == '"') {
-            len = slen - 2;
-            if (len > maxlen) {
-                VERBOSE (mapec, WARNING, PRINTF ("string too large (%d > %d) for '%s'\n", len, maxlen, str));
-                len = maxlen;
-            }
-            int j = 0;
-            for (int i = 1; i < len + 1; i++, j++) {
-                if ((str[i] == '\\') && (str[i + 1] == ' ')) {
-                    i++;
-                }
-                buffer[j] = str[i];
-            }
-            len = j;
-            VERBOSE (mapec, TRACE, buffer[len] = '\0'; PRINTF ("string[%d]: '%s'\n", len, buffer));
-        } else {
-            VERBOSE (mapec, ERROR, PRINTF ("incomplet string '%s'\n", str));
-        }
-    }
-
-    /* file payload: @filename */
-    else if (*str == '@') {
-        VERBOSE (mapec, TRACE, PRINTF ("file payload: @filename\n"));
-        FILE *fid = fopen (str + 1, "r");
-        if (fid != NULL) {
-            while ((len < maxlen) && (!feof (fid)) && (!ferror (fid))) {
-                len += fread (buffer + len, 1, maxlen - len, fid);
-            }
-            if (ferror (fid)) {
-                VERBOSE (mapec, ERROR, PRINTF ("can't read file '%s'\n", str));
-            } else if (!feof (fid)) {
-                fseek (fid, 0L, SEEK_SET);
-                fseek (fid, 0L, SEEK_END);
-                int flen = ftell (fid);
-                if (flen > maxlen) {
-                    VERBOSE (mapec, WARNING, PRINTF ("file too large (%d > %d) for '%s'\n", flen, maxlen, str));
-                }
-            }
-            fclose (fid);
-        } else {
-            VERBOSE (mapec, ERROR, PRINTF ("can't open file '%s'\n", str));
-        }
-    }
-
-    /* hexa payload: xx:xx:xx [0-9a-fA-F] */
-    else {
-        if (maxlen * 3 - 1 < slen) {
-            slen = maxlen * 3 - 1;
-        }
-        if (slen % 3 == 2) {
-            VERBOSE (mapec, TRACE, PRINTF ("hexa payload: xx:xx:xx\n"));
-            len = slen / 3 + 1;
-            if (len > maxlen) {
-                VERBOSE (mapec, WARNING, PRINTF ("string too large (%d > %d) for '%s'\n", len, maxlen, str));
-                len = maxlen;
-            }
-            for (int i = 0; i < len; i++) {
-                char digit[3] = {0};
-                char *ptr = NULL;
-                digit[0] = str[3 * i];
-                digit[1] = str[3 * i + 1];
-                buffer[i] = strtol (digit, &ptr, 16);
-                if ((*ptr != ':') && (*ptr != '\0') && (*ptr != ' ') && (*ptr != '\t')) {
-                    VERBOSE (mapec, ERROR, PRINTF ("unrecognize hexa-string (%d) '%s'\n", 3 * i, str));
-                    break;
-                }
-            }
-        }
-
-        /* unrecognize format */
-        else {
-            VERBOSE (mapec, WARNING, PRINTF ("can't parse buffer '%s'\n", str));
-        }
-    }
-    return len;
-}
-
-char *read_stream (FILE *sd, int *plen)
-{
-    VERBOSE (mapec, TRACE, PRINTF ("read_stream\n"));
-
-    /* read and store */
-    char *buffer = NULL;
-    size_t size = 0;
-    int blocklen = 0;
-    int length = 0;
-    do {
-        size += BUFMAX + (size == 0);
-        buffer = (char *) realloc (buffer, size);
-        memset (buffer + size - BUFMAX - 1, 0, BUFMAX + 1);
-        blocklen = fread (buffer + size - BUFMAX - 1, 1, BUFMAX, sd);
-        length += blocklen;
-    } while (blocklen > 0);
-
-    /* check size */
-    VERBOSE (mapec, DEBUG, PRINTF ("read length: %d\n", length));
-    if (length == 0) {
-        free (buffer);
-        buffer = NULL;
-    }
-
-    if (plen) {
-        *plen = length;
-    }
-
-    return buffer;
-}
-
-void print_message (FILE *fd, char *serv, int mode, uint8_t *payload, int len)
-{
-    fprintf (fd, "%c%s LEN=%d", mode ? 'T' : 'R', serv, len);
-    if (len > 0) {
-        int i;
-        fprintf (fd, " PAYLOAD=");
-        for (i = 0; i < len; i++) {
-            fprintf (fd, "%02x%c", payload[i], (i == len - 1) ? '\n' : ':');
-        }
-    }
-}
-
-typedef struct {
-    char *serv;
-    char *rxurl;
-    char *txurl;
-    int fid;
-} comm_t;
-
-#define MAXCOMMS 32
-
-int main (int argc, char **argv)
-{
-    char *filename = NULL;
-    char *logname = NULL;
-    char *url = NULL;
-    char *serv = NULL;
-    int mode = -1;
-    int nbcomms = 0;
-    comm_t comm_list[MAXCOMMS] = {0};
-    int reverse = 0;
-
-    /* get basename */
-    char *ptr = progname = argv[0];
-    while (*ptr) {
-        if ((*ptr == '/') || (*ptr == '\\')) {
-           progname = ptr + 1;
-        }
-        ptr++;
-    }
-
-    /* process argument */
-    while (argc-- > 1) {
-        char *arg = *(++argv);
-        if (arg[0] != '-') {
-            filename = arg;
-            continue;
-        }
-        char c = arg[1];
-        switch (c) {
-        case 'l':
-            arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
-            if (arg == NULL) {
-                VERBOSE (mapec, ERROR, PRINTF ("%s: log file not specified\n", progname));
-                return 1;
-            }
-            logname = arg;
-            break;
-        case 'n':
-            reverse = 1;
-            break;
-        case 'r':
-            arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
-            if (arg == NULL) {
-                VERBOSE (mapec, ERROR, PRINTF ("%s: receiver url not specified\n", progname));
-                return 1;
-            }
-            url = arg;
-            mode = 0;
-            break;
-        case 's':
-            arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
-            if (arg == NULL) {
-                VERBOSE (mapec, ERROR, PRINTF ("%s: service name not specified\n", progname));
-                return 1;
-            }
-            serv = arg;
-            break;
-        case 't':
-            arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
-            if (arg == NULL) {
-                VERBOSE (mapec, ERROR, PRINTF ("%s: transmitter url not specified\n", progname));
-                return 1;
-            }
-            url = arg;
-            mode = 1;
-            break;
-        case 'v':
-            arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
-            if (arg == NULL) {
-                VERBOSE (mapec, ERROR, PRINTF ("%s: verbose level not specified\n", progname));
-                return 1;
-            }
-            CHANGE_VERBOSE_LEVEL (mapec, atoi (arg));
-            break;
-        case 'h':
-        default:
-            printf ("usage: %s [-h] [-n] [-l log] [-r url] [-s serv] [-t url] [-v level] [file]\n", progname);
-            return (c != 'h');
-        }
-
-        /* store service info */
-        if (mode != -1) {
-            int id = -1;
-            comm_t *comm = NULL;
-            for (int i = 0; i < MAXCOMMS; i++) {
-                comm = comm_list + i;
-                if ((comm->serv) && (strcmp (serv, comm->serv) == 0)) {
-                    id = i;
-                    break;
-                }
-            }
-            if ((id == -1) && (nbcomms < MAXCOMMS)) {
-                id = nbcomms++;
-                comm = comm_list + id;
-            }
-            if (id == -1) {
-                VERBOSE (mapec, ERROR, PRINTF ("can't connect on url '%s'\n", url));
-                return -1;
-            }
-            if (comm->serv == NULL) {
-                comm->serv = strdup (serv);
-            }
-            if (mode == 0) {
-                free (comm->rxurl);
-                comm->rxurl = strdup (url);
-            } else {
-                free (comm->txurl);
-                comm->txurl = strdup (url);
-            }
-            mode = -1;
-        }
-    }
-
-    /* checks */
-    if (nbcomms == 0) {
-        VERBOSE (mapec, ERROR, PRINTF ("no communication channel\n"));
-        return -1;
-    }
-
-    /* init communication channel */
-    for (int i = 0; i < nbcomms; i++) {
-        comm_t *comm = comm_list + i;
-        if (comm->serv) {
-            if ((comm->rxurl == NULL) || (comm->txurl == NULL)) {
-                VERBOSE (mapec, ERROR, PRINTF ("missing an url (%s|%s)\n", comm->rxurl, comm->txurl));
-                return -1;
-            }
-            comm->fid = MAPEC_Connect (comm->rxurl, comm->txurl, NULL);
-            if (comm->fid < 0) {
-                VERBOSE (mapec, ERROR, PRINTF ("can't open communication for %s %s %s\n", comm->serv, comm->rxurl, comm->txurl));
-                return -1;
-            }
-        }
-    }
-
-    /* open script file */
-    FILE *fid = stdin;
-    if (filename != NULL) {
-        fid = fopen (filename, "r");
-        if (fid == NULL) {
-            VERBOSE (mapec, ERROR, PRINTF ("can't open script file '%s' for reading\n", filename));
-            return -1;
-        }
-    }
-    char *script = read_stream (fid, NULL);
-    if (fid != stdin) {
-        fclose (fid);
-    }
-    if (script == NULL) {
-        VERBOSE (mapec, ERROR, PRINTF ("no script read\n"));
-        return -1;
-    }
-
-    /* open log file */
-    FILE *log = NULL;
-    if (logname != NULL) {
-        if (strcmp (logname, "-") == 0) {
-            log = stdout;
-        } else {
-            log = fopen (logname, "w");
-            if (log == NULL) {
-                VERBOSE (mapec, ERROR, PRINTF ("can't open log file '%s' for writing\n", logname));
-                return -1;
-            }
-        }
-    }
-
-    /* signals */
-    signal(SIGINT, sig_handler);
-    signal(SIGTERM, sig_handler);
-
-    /* main loop */
-    int rc = 0;
-    ptr = script;
-    while (*ptr != '\0') {
-
-        /* read line */
-        char *line = ptr;
-        TEST_CHARS (ptr, "\n\r", 1);
-        *ptr++ = '\0';
-
-        /* clean line */
-        TEST_CHARS (line, " \t", 0);
-        if ((*line == '\0') || (*line == '#')) {
-            continue;
-        }
-
-        /* analyse line */
-        mode = -1;
-        if (*line == 'R') {
-            mode = 0 ^ reverse;
-        } else if (*line == 'T') {
-            mode = 1 ^ reverse;
-        } else if (strncmp (line, "SLEEP", 5) == 0) {
-            int duration = atoi (line + 5);
-            VERBOSE (mapec, INFO, PRINTF ("sleep %dms\n", duration));
-            usleep (duration * 1000);
-            continue;
-        }
-        if (mode == -1) {
-            VERBOSE (mapec, WARNING, PRINTF ("unrecognize line '%s'\n", line));
-            continue;
-        }
-
-        /* find service */
-        comm_t *comm = NULL;
-        int offset = 1;
-        int i;
-        for (i = 0; i < nbcomms; i++) {
-            comm_t *c = comm_list + i;
-            VERBOSE (mapec, TRACE, PRINTF ("test %s\n", c->serv));
-            if (strncmp (line + offset, c->serv, strlen (c->serv)) == 0) {
-                comm = c;
-                offset += strlen (c->serv);
-                break;
-            }
-        }
-        if (comm == NULL) {
-            VERBOSE (mapec, TRACE, PRINTF ("no MAPEC found '%s'\n", line));
-            continue;
-        }
-        VERBOSE (mapec, DEBUG, PRINTF ("work with %c[%s]\n", mode ? 'T' : 'R', comm->serv));
-
-        /* get values */
-        char *tmp = line + offset;
-        TEST_CHARS (tmp, " \t", 0);
-        if (strncmp (tmp, "PAYLOAD", 6) != 0) {
-            VERBOSE (mapec, WARNING, PRINTF ("can't parse line '%s' (%s)\n", line, tmp));
-            continue;
-        }
-        tmp += 7;
-        TEST_CHARS (tmp, " \t=", 0);
-        uint8_t payload[MAXPAYLOAD] = {0};
-        int len = parse_array (tmp, payload, MAXPAYLOAD);
-        if (len == 0) {
-            VERBOSE (mapec, WARNING, PRINTF ("can't parse line '%s'\n", line));
-            continue;
-        }
-
-        VERBOSE (mapec, TRACE, PRINTF ("payload length: %d\n", len));
-
-        /* transmit */
-        if (mode == 1) {
-            int txlen = MAPEC_Send (comm->fid, payload, len);
-            /* check payload */
-            if (txlen != len) {
-                VERBOSE (mapec, WARNING, PRINTF ("T%s: payload not sent %d/%d\n", comm->serv, len, txlen));
-            } else {
-                VERBOSE (mapec, INFO, PRINTF ("T%s: payload sent [%d]\n", comm->serv, txlen));
-            }
-
-            if (log) {
-                print_message (log, comm->serv, 1, payload, txlen);
-            }
-        } else { /* receive */
-            uint8_t rxpayload[MAXPAYLOAD] = {0};
-            int rxlen = MAPEC_Receive (comm->fid, rxpayload, MAXPAYLOAD);
-
-            /* check payload */
-            if ((rxlen != len) || ((memcmp (rxpayload, payload, rxlen) != 0))) {
-                VERBOSE (mapec, WARNING, PRINTF ("R%s: payload differed %d/%d\n", comm->serv, len, rxlen));
-            } else {
-                VERBOSE (mapec, INFO, PRINTF ("R%s: payload matched [%d]\n", comm->serv, rxlen));
-            }
-
-            if (log) {
-                print_message (log, comm->serv, 0, rxpayload, rxlen);
-           }
-        }
-    }
-
-    /* cleaning */
-    free (script);
-    while (nbcomms) {
-        comm_t *comm = comm_list + --nbcomms;
-        MAPEC_Close (comm->fid);
-        free (comm->serv);
-        free (comm->rxurl);
-        free (comm->txurl);
-    }
-    if (log) {
-        fclose (log);
-    }
-
-    return rc + GET_VERBOSE_ERRORS (mapec);
-}
-
-/* test: mapec_valid.exe -h | grep usage */
-/* test: mapec_valid.exe -l 2>&1 | grep 'log file not specified' */
-/* test: mapec_valid.exe -r 2>&1 | grep 'receiver url not specified' */
-/* test: mapec_valid.exe -s 2>&1 | grep 'service name not specified' */
-/* test: mapec_valid.exe -t 2>&1 | grep 'transmitter url not specified' */
-/* test: mapec_valid.exe -v 2>&1 | grep 'verbose level not specified' */
-
-/* test: mapec_valid.exe -s UDP o -r udp://localhost:1234 2>&1 | grep 'missing an url' */
-/* test: echo | mapec_valid.exe -s UDP -r udp://localhost:1234 -t udp://localhost:1235 */
-/* test: mapec_valid.exe -n -s UDP -r udp://localhost:1234 -t udp://localhost:1235 script-udp.mapec & pid=$!; sleep 1; mapec_valid.exe -s UDP -r udp://localhost:1235 -t udp://localhost:1234 script-udp.mapec | awk '{print "<2>", $0}' */
-/* test: mapec_valid.exe -s TUN0 -r tun://tun0 2>&1 | grep 'missing an url' */
-/* test: echo | mapec_valid.exe -s TUN0 -r tun://tun0 -t tun://1.2.3.4 */
-
-/* vim: set ts=4 sw=4 si et: */
diff --git a/script-error.mapec b/script-error.mapec
new file mode 100644 (file)
index 0000000..5e74209
--- /dev/null
@@ -0,0 +1,25 @@
+# Test script
+
+TUDP PAYLOAD=@plaintext.txt text not ignored
+SLEEP 100
+
+TUDP PAYLOAD=@nofile.txt
+SLEEP 100
+
+TUDP PAYLOAD=@udp_valid.c
+SLEEP 100
+
+TUDP PAYLOAD="This is an unfinished text
+SLEEP 100
+
+TUDP PAYLOAD="This is a text" text not ignored
+SLEEP 100
+
+TUDP NOTPAYLOAD="This is a text"
+SLEEP 100
+
+TUDP PAYLOAD=01:02:03:04:05:06:07:08:09:0a:0b:0c:0d:0e:0f:10 text not ignored
+SLEEP 100
+
+TUDP PAYLOAD=01:02:fo:ob:ae:06:07:08:09:0a:0b:0c:0d:0e:0f:10
+SLEEP 100
diff --git a/udp_valid.c b/udp_valid.c
new file mode 100644 (file)
index 0000000..10fea07
--- /dev/null
@@ -0,0 +1,516 @@
+/*
+  File name        : udp_valid.c
+  Projet           : MERLIN
+  Date of creation : 2025/05/23
+  Version          : 1.0
+  Copyright        : Thales SIX
+  Author           : Laurent Mazet <laurent.mazet@thalesgroup.com>
+
+  Description      : Minimal API for Packet Exchange Commmunication (UDP)
+                     validation program
+
+  History          :
+  - initial version
+*/
+
+/* depend: */
+/* cflags: */
+/* linker: mapec.o */
+
+#include <errno.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mapec.h"
+#include "verbose.h"
+
+char *progname = NULL;
+
+int stop = 0;
+
+#define BUFMAX 4096
+
+#define MAXPAYLOAD 1500
+
+void sig_handler (int sig)
+{
+    switch (sig) {
+    case SIGINT:
+        //stop = 1;
+        exit (0);
+        break;
+    case SIGTERM:
+        exit (0);
+        break;
+    }
+}
+
+#define TEST_CHARS(str, delim, stop)                      \
+    while (*str != '\0') {                                \
+        int i, stat = 0;                                  \
+        for (i = 0; (delim[i] != '\0') && (!stat); i++) { \
+            if (*str == delim[i]) {                       \
+                stat = 1;                                 \
+            }                                             \
+        }                                                 \
+        if (stat == stop) {                               \
+            break;                                        \
+        }                                                 \
+        str++;                                            \
+    }
+
+int parse_array (char *str, uint8_t *buffer, int maxlen)
+{
+    int len = 0;
+    int slen = strlen (str);
+
+    /* string payload: "..." (space must be protected by '\') */
+    if ((*str == '"') && (slen > 1)) {
+        VERBOSE (mapec, TRACE, PRINTF ("string payload: \"...\"\n"));
+        if (maxlen < slen - 2) slen = maxlen + 2;
+        if (str[slen - 1] == '"') {
+            len = slen - 2;
+            if (len > maxlen) {
+                VERBOSE (mapec, WARNING, PRINTF ("string too large (%d > %d) for '%s'\n", len, maxlen, str));
+                len = maxlen;
+            }
+            int j = 0;
+            for (int i = 1; i < len + 1; i++, j++) {
+                if ((str[i] == '\\') && (str[i + 1] == ' ')) {
+                    i++;
+                }
+                buffer[j] = str[i];
+            }
+            len = j;
+            VERBOSE (mapec, TRACE, buffer[len] = '\0'; PRINTF ("string[%d]: '%s'\n", len, buffer));
+        } else {
+            VERBOSE (mapec, DEBUG, PRINTF ("incomplet string '%s'\n", str));
+        }
+    }
+
+    /* file payload: @filename */
+    else if (*str == '@') {
+        VERBOSE (mapec, TRACE, PRINTF ("file payload: @filename\n"));
+        FILE *fid = fopen (str + 1, "r");
+        if (fid != NULL) {
+            while ((len < maxlen) && (!feof (fid)) && (!ferror (fid))) {
+                len += fread (buffer + len, 1, maxlen - len, fid);
+            }
+            if (ferror (fid)) {
+                VERBOSE (mapec, ERROR, PRINTF ("can't read file '%s'\n", str));
+            } else if (!feof (fid)) {
+                fseek (fid, 0L, SEEK_SET);
+                fseek (fid, 0L, SEEK_END);
+                int flen = ftell (fid);
+                if (flen > maxlen) {
+                    VERBOSE (mapec, WARNING, PRINTF ("file too large (%d > %d) for '%s'\n", flen, maxlen, str));
+                }
+            }
+            fclose (fid);
+        } else {
+            VERBOSE (mapec, DEBUG, PRINTF ("can't open file '%s'\n", str));
+        }
+    }
+
+    /* hexa payload: xx:xx:xx [0-9a-fA-F] */
+    else {
+        if (maxlen * 3 - 1 < slen) {
+            slen = maxlen * 3 - 1;
+        }
+        if (slen % 3 == 2) {
+            VERBOSE (mapec, TRACE, PRINTF ("hexa payload: xx:xx:xx\n"));
+            len = slen / 3 + 1;
+            if (len > maxlen) {
+                VERBOSE (mapec, WARNING, PRINTF ("string too large (%d > %d) for '%s'\n", len, maxlen, str));
+                len = maxlen;
+            }
+            for (int i = 0; i < len; i++) {
+                char digit[3] = {0};
+                char *ptr = NULL;
+                digit[0] = str[3 * i];
+                digit[1] = str[3 * i + 1];
+                buffer[i] = strtol (digit, &ptr, 16);
+                if ((*ptr != ':') && (*ptr != '\0') && (*ptr != ' ') && (*ptr != '\t')) {
+                    VERBOSE (mapec, DEBUG, PRINTF ("unrecognize hexa-string (%d) '%s'\n", 3 * i, str));
+                    len = 0;
+                    break;
+                }
+            }
+        }
+
+        /* unrecognize format */
+        else {
+            VERBOSE (mapec, DEBUG, PRINTF ("can't parse buffer '%s'\n", str));
+        }
+    }
+    return len;
+}
+
+char *read_stream (FILE *sd, int *plen)
+{
+    VERBOSE (mapec, TRACE, PRINTF ("read_stream\n"));
+
+    /* read and store */
+    char *buffer = NULL;
+    size_t size = 0;
+    int blocklen = 0;
+    int length = 0;
+    do {
+        size += BUFMAX + (size == 0);
+        buffer = (char *) realloc (buffer, size);
+        memset (buffer + size - BUFMAX - 1, 0, BUFMAX + 1);
+        blocklen = fread (buffer + size - BUFMAX - 1, 1, BUFMAX, sd);
+        length += blocklen;
+    } while (blocklen > 0);
+
+    /* check size */
+    VERBOSE (mapec, DEBUG, PRINTF ("read length: %d\n", length));
+    if (length == 0) {
+        free (buffer);
+        buffer = NULL;
+    }
+
+    if (plen) {
+        *plen = length;
+    }
+
+    return buffer;
+}
+
+void print_message (FILE *fd, char *serv, int mode, uint8_t *payload, int len)
+{
+    fprintf (fd, "%c%s LEN=%d", mode ? 'T' : 'R', serv, len);
+    if (len > 0) {
+        int i;
+        fprintf (fd, " PAYLOAD=");
+        for (i = 0; i < len; i++) {
+            fprintf (fd, "%02x%c", payload[i], (i == len - 1) ? '\n' : ':');
+        }
+    }
+}
+
+typedef struct {
+    char *serv;
+    char *rxurl;
+    char *txurl;
+    int fid;
+} comm_t;
+
+#define MAXCOMMS 32
+
+int main (int argc, char **argv)
+{
+    char *filename = NULL;
+    char *logname = NULL;
+    char *url = NULL;
+    char *serv = NULL;
+    int mode = -1;
+    int nbcomms = 0;
+    comm_t comm_list[MAXCOMMS] = {0};
+    int reverse = 0;
+
+    /* get basename */
+    char *ptr = progname = argv[0];
+    while (*ptr) {
+        if ((*ptr == '/') || (*ptr == '\\')) {
+           progname = ptr + 1;
+        }
+        ptr++;
+    }
+
+    /* process argument */
+    while (argc-- > 1) {
+        char *arg = *(++argv);
+        if (arg[0] != '-') {
+            filename = arg;
+            continue;
+        }
+        char c = arg[1];
+        switch (c) {
+        case 'l':
+            arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
+            if (arg == NULL) {
+                VERBOSE (mapec, ERROR, PRINTF ("%s: log file not specified\n", progname));
+                return 1;
+            }
+            logname = arg;
+            break;
+        case 'n':
+            reverse = 1;
+            break;
+        case 'r':
+            arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
+            if (arg == NULL) {
+                VERBOSE (mapec, ERROR, PRINTF ("%s: receiver url not specified\n", progname));
+                return 1;
+            }
+            url = arg;
+            mode = 0;
+            break;
+        case 's':
+            arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
+            if (arg == NULL) {
+                VERBOSE (mapec, ERROR, PRINTF ("%s: service name not specified\n", progname));
+                return 1;
+            }
+            serv = arg;
+            break;
+        case 't':
+            arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
+            if (arg == NULL) {
+                VERBOSE (mapec, ERROR, PRINTF ("%s: transmitter url not specified\n", progname));
+                return 1;
+            }
+            url = arg;
+            mode = 1;
+            break;
+        case 'v':
+            arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
+            if (arg == NULL) {
+                VERBOSE (mapec, ERROR, PRINTF ("%s: verbose level not specified\n", progname));
+                return 1;
+            }
+            CHANGE_VERBOSE_LEVEL (mapec, atoi (arg));
+            break;
+        case 'h':
+        default:
+            printf ("usage: %s [-h] [-n] [-l log] [-r url] [-s serv] [-t url] [-v level] [file]\n", progname);
+            return (c != 'h');
+        }
+
+        /* store service info */
+        if (mode != -1) {
+            int id = -1;
+            comm_t *comm = NULL;
+            for (int i = 0; i < MAXCOMMS; i++) {
+                comm = comm_list + i;
+                if ((comm->serv) && (strcmp (serv, comm->serv) == 0)) {
+                    id = i;
+                    break;
+                }
+            }
+            if ((id == -1) && (nbcomms < MAXCOMMS)) {
+                id = nbcomms++;
+                comm = comm_list + id;
+            }
+            if (id == -1) {
+                VERBOSE (mapec, ERROR, PRINTF ("can't connect on url '%s'\n", url));
+                return -1;
+            }
+            if (comm->serv == NULL) {
+                comm->serv = strdup (serv);
+            }
+            if (mode == 0) {
+                free (comm->rxurl);
+                comm->rxurl = strdup (url);
+            } else {
+                free (comm->txurl);
+                comm->txurl = strdup (url);
+            }
+            mode = -1;
+        }
+    }
+
+    /* checks */
+    if (nbcomms == 0) {
+        VERBOSE (mapec, ERROR, PRINTF ("no communication channel\n"));
+        return -1;
+    }
+
+    /* init communication channel */
+    for (int i = 0; i < nbcomms; i++) {
+        comm_t *comm = comm_list + i;
+        if (comm->serv) {
+            if ((comm->rxurl == NULL) || (comm->txurl == NULL)) {
+                VERBOSE (mapec, ERROR, PRINTF ("missing an url (%s|%s)\n", comm->rxurl, comm->txurl));
+                return -1;
+            }
+            comm->fid = MAPEC_Connect (comm->rxurl, comm->txurl, NULL);
+            if (comm->fid < 0) {
+                VERBOSE (mapec, ERROR, PRINTF ("can't open communication for %s %s %s\n", comm->serv, comm->rxurl, comm->txurl));
+                return -1;
+            }
+        }
+    }
+
+    /* open script file */
+    FILE *fid = stdin;
+    if (filename != NULL) {
+        fid = fopen (filename, "r");
+        if (fid == NULL) {
+            VERBOSE (mapec, ERROR, PRINTF ("can't open script file '%s' for reading\n", filename));
+            return -1;
+        }
+    }
+    char *script = read_stream (fid, NULL);
+    if (fid != stdin) {
+        fclose (fid);
+    }
+    if (script == NULL) {
+        VERBOSE (mapec, ERROR, PRINTF ("no script read\n"));
+        return -1;
+    }
+
+    /* open log file */
+    FILE *log = NULL;
+    if (logname != NULL) {
+        if (strcmp (logname, "-") == 0) {
+            log = stdout;
+        } else {
+            log = fopen (logname, "w");
+            if (log == NULL) {
+                VERBOSE (mapec, ERROR, PRINTF ("can't open log file '%s' for writing\n", logname));
+                return -1;
+            }
+        }
+    }
+
+    /* signals */
+    signal(SIGINT, sig_handler);
+    signal(SIGTERM, sig_handler);
+
+    /* main loop */
+    int rc = 0;
+    ptr = script;
+    while (*ptr != '\0') {
+
+        /* read line */
+        char *line = ptr;
+        TEST_CHARS (ptr, "\n\r", 1);
+        *ptr++ = '\0';
+
+        /* clean line */
+        TEST_CHARS (line, " \t", 0);
+        if ((*line == '\0') || (*line == '#')) {
+            continue;
+        }
+
+        /* analyse line */
+        mode = -1;
+        if (*line == 'R') {
+            mode = 0 ^ reverse;
+        } else if (*line == 'T') {
+            mode = 1 ^ reverse;
+        } else if (strncmp (line, "SLEEP", 5) == 0) {
+            int duration = atoi (line + 5);
+            VERBOSE (mapec, INFO, PRINTF ("sleep %dms\n", duration));
+            usleep (duration * 1000);
+            continue;
+        }
+        if (mode == -1) {
+            VERBOSE (mapec, WARNING, PRINTF ("unrecognize line '%s'\n", line));
+            continue;
+        }
+
+        /* find service */
+        comm_t *comm = NULL;
+        int offset = 1;
+        int i;
+        for (i = 0; i < nbcomms; i++) {
+            comm_t *c = comm_list + i;
+            VERBOSE (mapec, TRACE, PRINTF ("test %s\n", c->serv));
+            if (strncmp (line + offset, c->serv, strlen (c->serv)) == 0) {
+                comm = c;
+                offset += strlen (c->serv);
+                break;
+            }
+        }
+        if (comm == NULL) {
+            VERBOSE (mapec, TRACE, PRINTF ("no MAPEC found '%s'\n", line));
+            continue;
+        }
+        VERBOSE (mapec, DEBUG, PRINTF ("work with %c[%s]\n", mode ? 'T' : 'R', comm->serv));
+
+        /* get values */
+        char *tmp = line + offset;
+        TEST_CHARS (tmp, " \t", 0);
+        if (strncmp (tmp, "PAYLOAD", 6) != 0) {
+            VERBOSE (mapec, WARNING, PRINTF ("can't parse line '%s' (%s)\n", line, tmp));
+            continue;
+        }
+        tmp += 7;
+        TEST_CHARS (tmp, " \t=", 0);
+        uint8_t payload[MAXPAYLOAD] = {0};
+        int len = parse_array (tmp, payload, MAXPAYLOAD);
+        if (len == 0) {
+            VERBOSE (mapec, WARNING, PRINTF ("can't parse line '%s'\n", line));
+            continue;
+        }
+
+        VERBOSE (mapec, TRACE, PRINTF ("payload length: %d\n", len));
+
+        /* transmit */
+        if (mode == 1) {
+            int txlen = MAPEC_Send (comm->fid, payload, len);
+            /* check payload */
+            if (txlen != len) {
+                VERBOSE (mapec, WARNING, PRINTF ("T%s: payload not sent %d/%d\n", comm->serv, len, txlen));
+            } else {
+                VERBOSE (mapec, INFO, PRINTF ("T%s: payload sent [%d]\n", comm->serv, txlen));
+            }
+
+            if (log) {
+                print_message (log, comm->serv, 1, payload, txlen);
+            }
+        } else { /* receive */
+            uint8_t rxpayload[MAXPAYLOAD] = {0};
+            int rxlen = MAPEC_Receive (comm->fid, rxpayload, MAXPAYLOAD);
+
+            /* check payload */
+            if ((rxlen != len) || ((memcmp (rxpayload, payload, rxlen) != 0))) {
+                VERBOSE (mapec, WARNING, PRINTF ("R%s: payload differed %d/%d\n", comm->serv, len, rxlen));
+            } else {
+                VERBOSE (mapec, INFO, PRINTF ("R%s: payload matched [%d]\n", comm->serv, rxlen));
+            }
+
+            if (log) {
+                print_message (log, comm->serv, 0, rxpayload, rxlen);
+           }
+        }
+    }
+
+    /* cleaning */
+    free (script);
+    while (nbcomms) {
+        comm_t *comm = comm_list + --nbcomms;
+        MAPEC_Close (comm->fid);
+        free (comm->serv);
+        free (comm->rxurl);
+        free (comm->txurl);
+    }
+    if (log) {
+        fclose (log);
+    }
+
+    return rc + GET_VERBOSE_ERRORS (mapec);
+}
+
+/* test: udp_valid.exe -h | grep usage */
+/* test: chmod a+w *.gcda */
+/* test: udp_valid.exe -l 2>&1 | grep 'log file not specified' */
+/* test: udp_valid.exe -r 2>&1 | grep 'receiver url not specified' */
+/* test: udp_valid.exe -s 2>&1 | grep 'service name not specified' */
+/* test: udp_valid.exe -t 2>&1 | grep 'transmitter url not specified' */
+/* test: udp_valid.exe -v 2>&1 | grep 'verbose level not specified' */
+
+/* test: udp_valid.exe -s UDP o -r udp://localhost:1234; test $? -ne 0 */
+/* test: udp_valid.exe -s UDP -r udp://localhost -t udp://localhost:1235:1234; test $? -ne 0 */
+/* test: udp_valid.exe -s UDP -r udp://localhost:1234 -t udp://localhost; test $? -ne 0 */
+/* test: udp_valid.exe -s UDP -r udp://nowhere:1234 -t udp://localhost:1235; test $? -ne 0 */
+/* test: udp_valid.exe -s UDP -r udp://localhost:1234 -t udp://nowhere:1235; test $? -ne 0 */
+/* test: udp_valid.exe -s UDP -r udp://localhost:1234 -t tun://localhost:1235; test $? -ne 0 */
+/* test: sudo -u `awk -F: '/sh$/ && $3 != 0 {print $1; exit}' /etc/passwd` udp_valid.exe -s UDP -r udp://localhost:12 -t udp://localhost:35; test $? -ne 0 */
+
+/* test: echo | udp_valid.exe -s UDP -r udp://localhost:1234 -t udp://localhost:1235 */
+
+/* test: udp_valid.exe -n -s UDP -r udp://localhost:1234 -t udp://localhost:1235 script-udp.mapec & pid=$!; sleep 1; kill -INT $pid */
+/* test: udp_valid.exe -n -s UDP -r udp://localhost:1234 -t udp://localhost:1235 script-udp.mapec & pid=$!; sleep 1; kill -TERM $pid */
+/* test: udp_valid.exe -s UDP -r udp://localhost:1234 -t udp://localhost:1235 script-error.mapec; test $? -eq $(grep -c TUDP script-error.mapec) */
+/* test: udp_valid.exe -n -s UDP -r udp://localhost:1234 -t udp://localhost:1235 script-udp.mapec & pid=$!; sleep 1; udp_valid.exe -s UDP -r udp://localhost:1235 -t udp://localhost:1234 script-udp.mapec | awk '{print "<2>", $0}' */
+/* test: udp_valid.exe -l - -n -s UDP -r udp://localhost:1234 -t udp://localhost:1235 script-udp.mapec & pid=$!; sleep 1; udp_valid.exe -l script-udp.log -s UDP -r udp://localhost:1235 -t udp://localhost:1234 script-udp.mapec | awk '{print "<2>", $0}' */
+
+/* vim: set ts=4 sw=4 si et: */
diff --git a/ulvpn.c b/ulvpn.c
index d815d66ff3e0a4b4d199b7e97e962c4e4edb87ee..6138c733cf6badb9006a5f1991b76b3793bbf806 100644 (file)
--- a/ulvpn.c
+++ b/ulvpn.c
@@ -244,6 +244,7 @@ int main (int argc, char **argv)
 }
 
 /* test: ulvpn.exe -h | grep usage */
+/* test: chmod a+w *.gcda */
 /* test: ulvpn.exe help 2>&1 | grep usage */
 /* test: ulvpn.exe -d 2>&1 | grep 'dev tun not specified' */
 /* test: ulvpn.exe -l 2>&1 | grep 'local tun not specified' */
@@ -253,7 +254,7 @@ int main (int argc, char **argv)
 /* test: ulvpn.exe -v 2>&1 | grep 'verbose level not specified' */
 /* test: ulvpn.exe -V 2>&1 | grep 'verbose level not specified' */
 
-/* test: sudo `awk -F: '/sh$/ && $3 != 0 {print $1; exit}' /etc/passwd` ulvpn.exe; test $? -ne 0 */
+/* test: sudo -u `awk -F: '/sh$/ && $3 != 0 {print $1; exit}' /etc/passwd` ulvpn.exe; test $? -ne 0 */
 
 /* test: ulvpn.exe -d tun://tun0:-1; test $? -ne 0 */
 /* test: ulvpn.exe -d tun://tun1; test $? -ne 0 */