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);
+++ /dev/null
-/*
- 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: */
--- /dev/null
+# 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
--- /dev/null
+/*
+ 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: */
}
/* 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' */
/* 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 */