RANLIB ?= ranlib
#INCLUDES = -I../debug -D__MEMORY_ALLOCATION__
+INCLUDES = -D_DEFAULT_SOURCE=1
INCLUDES += -DVERBOSE_COLOR=1
#INCLUDES += -DVERBOSE_LOCATION=1
OFLAGS = -O4 -Os
- initial version
*/
+#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
+#include <linux/if_tun.h>
+#include <linux/sockios.h>
+#include <net/if.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
+#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/socket.h>
+#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
*/
typedef enum {
MAPEC_error_e = 0,
- MAPEC_udp_e
+ MAPEC_udp_e,
+ MAPEC_tun_e
} MAPEC_type_t;
/**
atexit (free_all_mapecs);
}
-int parse_protocol (MAPEC_addr_t *addr, char *url)
+int parse_protocol (MAPEC_type_t *type, char *url)
{
VERBOSE (mapec, TRACE, PRINTF ("parse_protocol\n"));
int rc = -1;
- MAPEC_type_t type = MAPEC_error_e;
+ MAPEC_type_t newtype = MAPEC_error_e;
if (strncmp (url, "udp://", 6) == 0) {
- type = MAPEC_udp_e;
+ newtype = MAPEC_udp_e;
+ rc = 6;
+ } else if (strncmp (url, "tun://", 6) == 0) {
+ newtype = MAPEC_tun_e;
rc = 6;
}
- if (addr->type == MAPEC_error_e) {
- addr->type = type;
- } else if (addr->type != type) {
+ if (*type == MAPEC_error_e) {
+ *type = newtype;
+ } else if (*type != newtype) {
rc = -1;
}
addr->sin_family = AF_INET;
addr->sin_port = htons (atoi (port));
-
+
VERBOSE (mapec, INFO, PRINTF ("parse URL -> %s %s\n", hostname, port));
if (hostname[0] != '*') {
return 0;
}
-int MAPEC_Connect (char *local_address, char * remote_address)
+int connect_udp (MAPEC_addr_t *mapec, char *local_address, char *remote_address)
{
- VERBOSE (mapec, TRACE, PRINTF ("MAPEC_Connect\n"));
-
- MAPEC_addr_t mapec = { 0 };
- int rc;
+ VERBOSE (mapec, TRACE, PRINTF ("connect_udp\n"));
/* parse local url */
VERBOSE (mapec, DEBUG, PRINTF ("MAPEC local addr %s\n", local_address));
- rc = parse_protocol (&mapec, local_address);
- if ((rc <= 0) || (parse_address (&mapec.addrin, local_address + rc) < 0)) {
+ if (parse_address (&mapec->addrin, local_address) < 0) {
VERBOSE (mapec, ERROR, PRINTF ("can't parse local url\n"));
errno = EINVAL;
return -1;
}
- VERBOSE (mapec, DEBUG, PRINTF ("local port -> %d\n", ntohs (mapec.addrin.sin_port)));
+ VERBOSE (mapec, DEBUG, PRINTF ("local port -> %d\n", ntohs (mapec->addrin.sin_port)));
/* parse remote url */
VERBOSE (mapec, DEBUG, PRINTF ("MAPEC remote addr %s\n", remote_address));
- rc = parse_protocol (&mapec, remote_address);
- if ((rc <= 0) || (parse_address (&mapec.addrout, remote_address + rc) < 0)) {
+ if (parse_address (&mapec->addrout, remote_address) < 0) {
VERBOSE (mapec, ERROR, PRINTF ("can't parse remote url\n"));
errno = EINVAL;
return -1;
}
- VERBOSE (mapec, DEBUG, PRINTF ("remote port -> %d\n", ntohs (mapec.addrout.sin_port)));
+ VERBOSE (mapec, DEBUG, PRINTF ("remote port -> %d\n", ntohs (mapec->addrout.sin_port)));
/* create socket */
int fid = socket (PF_INET, SOCK_DGRAM, 0);
/* bind on local */
int val = 1;
setsockopt (fid, SOL_SOCKET, SO_REUSEADDR, (int *)&val, sizeof (val));
- if (bind (fid, (struct sockaddr *)&mapec.addrin, sizeof (mapec.addrin)) < 0) {
+ if (bind (fid, (struct sockaddr *)&mapec->addrin, sizeof (mapec->addrin)) < 0) {
VERBOSE (mapec, ERROR, PRINTF ("can't bind socket %d\n", fid));
return -1;
}
/* connect on remote */
- if (connect (fid, (struct sockaddr *)&mapec.addrout, sizeof (mapec.addrout)) < 0) {
+ if (connect (fid, (struct sockaddr *)&mapec->addrout, sizeof (mapec->addrout)) < 0) {
VERBOSE (mapec, ERROR, PRINTF ("can't connect socket %d\n", fid));
return -1;
}
-
- MAPEC_list[fid] = mapecdup (&mapec);
+
+ return fid;
+}
+
+#define ifreq_offsetof(x) offsetof(struct ifreq, x)
+
+int connect_tun (MAPEC_addr_t *mapec, char *device_name, char *ip_address)
+{
+
+ VERBOSE (mapec, TRACE, PRINTF ("connect_tun\n"));
+
+ /* request a TUN device */
+ int fid = open ("/dev/net/tun", O_RDWR);
+ if (fid < 0) {
+ VERBOSE (mapec, ERROR, PRINTF ("can't open a tun device '%s'\n", device_name));
+ return -1;
+ }
+
+ /* link to named device */
+ struct ifreq ifr = { 0 };
+ ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
+ if (ioctl (fid, TUNSETIFF, &ifr) < 0) {
+ VERBOSE (mapec, ERROR, PRINTF ("can't link to named device '%s'\n", device_name));
+ return -1;
+ }
+
+ /* Create a channel to the NET kernel. */
+ int sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0) {
+ VERBOSE (mapec, ERROR, PRINTF ("can't accept socket %d\n", sock));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* get interface name */
+ ifr.ifr_flags = 0;
+ strncpy(ifr.ifr_name, device_name, IFNAMSIZ);
+
+ /* set ip address */
+ mapec->addrin.sin_family = AF_INET;
+ mapec->addrin.sin_port = 0;
+ mapec->addrin.sin_addr.s_addr = inet_addr (ip_address);
+ memcpy (&ifr.ifr_addr, &mapec->addrin, sizeof (struct sockaddr));
+
+ if ((ioctl (sock, SIOCSIFADDR, &ifr) < 0) || (ioctl (sock, SIOCGIFFLAGS, &ifr) < 0)) {
+ VERBOSE (mapec, ERROR, PRINTF ("can't set ip address '%s' on tun device '%s'\n", ip_address, device_name));
+ return -1;
+ }
+
+ ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
+ if (ioctl (sock, SIOCSIFFLAGS, &ifr) < 0) {
+ VERBOSE (mapec, ERROR, PRINTF ("can't activate tun interface '%s'\n", device_name));
+ return -1;
+ }
+ close (sock);
+
+ return fid;
+}
+
+int MAPEC_Connect (char *arg1, char *arg2)
+{
+
+ VERBOSE (mapec, TRACE, PRINTF ("MAPEC_Connect\n"));
+
+ MAPEC_addr_t mapec = { 0 };
+
+ /* check type */
+ int rc = parse_protocol (&mapec.type, arg1);
+ if (arg2) {
+ rc = parse_protocol (&mapec.type, arg2);
+ }
+ if (rc < 0) {
+ VERBOSE (mapec, ERROR, PRINTF ("non coherent protocol '%s' <> '%s'\n", arg1, (arg2) ? arg2 : ""));
+ errno = EINVAL;
+ return -1;
+ }
+
+ int fid;
+ switch (mapec.type) {
+ case MAPEC_udp_e:
+ fid = connect_udp (&mapec, arg1 + rc, arg2 + rc);
+ break;
+
+ case MAPEC_tun_e:
+ fid = connect_tun (&mapec, arg1 + rc, arg2 + rc);
+ break;
+
+ default:
+ fid = -1;
+ }
+
+ if (fid >= 0) {
+ MAPEC_list[fid] = mapecdup (&mapec);
+ }
return fid;
}
Establish a connection between a local URL and a remote URL. Block
until connection is established or refused.
- @param local_address local address of the MAPEC with the following
- syntax: 'udp://hostname:port' or 'tun://device'.
- @param remote_address same format as for local_address. For TUN,
- remote address is not usesfull.
+ @param arg1 first argument
+ @param arg2 second argrument
+
+ For UDP connection, arguements are local and remote addresses. The
+ syntax is 'udp://hostname:port'
+ For TUN connection, first argument is an url, second argument is the
+ IP address of the tun device. The syntax is tun://device and tun://ip
@return a new file descriptor associated with this connection
@see MAPEC_Send()
@see MAPEC_Receive()
*/
-int MAPEC_Connect (char *local_address, char *remote_address);
+int MAPEC_Connect (char *arg1, char *arg2);
/**
@ingroup MAPEC
#include "mapec.h"
-int MAPEC_Send_UDP_OK = 0;
-int MAPEC_Echo_UDP_OK = 0;
+char *progname = NULL;
+char *client_local_url = "udp://localhost:13501";
+char *client_remote_url = "udp://localhost:12501";
+char *server_local_url = "udp://localhost:12501";
+char *server_remote_url = "udp://localhost:13501";
+
+int MAPEC_Send_OK = 0;
+int MAPEC_Echo_OK = 0;
#define UNUSED __attribute__ ((unused))
-void *udp_client (UNUSED void *dummy)
+void *client (UNUSED void *dummy)
{
- VERBOSE (mapec, TRACE, PRINTF ("test_client\n"));
+ VERBOSE (mapec, TRACE, PRINTF ("client\n"));
int count;
unsigned char tx_data[10][1500];
int tx_len[10];
- int fid = MAPEC_Connect ("udp://localhost:13501", "udp://localhost:12501");
+ int fid = MAPEC_Connect (client_local_url, client_remote_url);
if (fid < 0) {
VERBOSE (mapec, WARNING, PRINTF ("client MAPEC_Connect error\n"));
- MAPEC_Echo_UDP_OK = 0;
+ MAPEC_Echo_OK = 0;
return NULL;
}
VERBOSE (mapec, INFO, PRINTF ("client connected to server, trying to exchange %d messages\n", nb_messages));
for (count = 0; count < nb_messages; count++) {
-
+
tx_len[count] = rand () % sizeof (tx_data[count]);
for (int i = 0; i < tx_len[count]; i++)
tx_data[count][i] = rand () % 256;
int rc = MAPEC_Send (fid, tx_data[count], tx_len[count]);
if (rc < 0) {
VERBOSE (mapec, WARNING, PRINTF ("client MAPEC_Send tx error (%d/%d-%d)\n", rc, tx_len[count], errno));
- MAPEC_Echo_UDP_OK = 0;
+ MAPEC_Echo_OK = 0;
return NULL;
}
if (tx_len[count] != rc) {
VERBOSE (mapec, WARNING, PRINTF ("client MAPEC_Send tx len error tx=%d rc=%d\n", tx_len[count], rc));
- MAPEC_Echo_UDP_OK = 0;
+ MAPEC_Echo_OK = 0;
return NULL;
}
VERBOSE (mapec, DEBUG, PRINTF ("client MAPEC_Send ok (%d)\n", tx_len[count]));
if (tx_len[count] != rx_len) {
VERBOSE (mapec, WARNING, PRINTF ("client MAPEC_Receive rx len error : tx=%d / rx=%d\n", tx_len[count], rx_len));
- MAPEC_Echo_UDP_OK = 0;
+ MAPEC_Echo_OK = 0;
return NULL;
}
if (memcmp (rx_data, tx_data[count], tx_len[count]) != 0 ) {
VERBOSE (mapec, WARNING, PRINTF ("client MAPEC_Receive rx corrupted data\n"));
- MAPEC_Echo_UDP_OK = 0;
+ MAPEC_Echo_OK = 0;
return NULL;
}
}
MAPEC_Close (fid);
VERBOSE (mapec, INFO, PRINTF ("client end of test, %d echo processed\n", count));
- MAPEC_Echo_UDP_OK = 1;
+ MAPEC_Echo_OK = 1;
return NULL;
}
-void *udp_server (UNUSED void *dummy)
+void *server (UNUSED void *dummy)
{
- VERBOSE (mapec, TRACE, PRINTF ("udp_server\n"));
+ VERBOSE (mapec, TRACE, PRINTF ("server\n"));
- int fid = MAPEC_Connect ("udp://localhost:12501", "udp://localhost:13501");
+ int fid = MAPEC_Connect (server_local_url, server_remote_url);
if (fid < 0) {
- VERBOSE (mapec, ERROR, PRINTF ("MAPEC_Connect (%d)", fid));
+ VERBOSE (mapec, ERROR, PRINTF ("MAPEC_Connect (%d)\n", fid));
exit (1);
}
- VERBOSE (mapec, INFO, PRINTF ("udp_server waiting for data\n"));
+ VERBOSE (mapec, INFO, PRINTF ("server waiting for data\n"));
while (1) {
unsigned char data[8192];
break;
}
- VERBOSE (mapec, INFO, PRINTF ("udp_server receive data len=%d, sending echo\n", rx_len));
+ VERBOSE (mapec, INFO, PRINTF ("server receive data len=%d, sending echo\n", rx_len));
usleep (1e4);
int tx_len = MAPEC_Send (fid, data, rx_len);
if (tx_len == rx_len) {
- MAPEC_Send_UDP_OK = 1;
+ MAPEC_Send_OK = 1;
}
}
int main (int argc, char **argv)
{
- /* process arguments */
- if (argc > 1) {
- CHANGE_VERBOSE_LEVEL (mapec, atoi (argv[1]));
- argc--;
+ /* get basename */
+ char *pt = progname = argv[0];
+ while (*pt) {
+ if ((*pt == '/') || (*pt == '\\')) {
+ progname = pt + 1;
+ }
+ pt++;
}
- if (argc > 1) {
- printf ("usage: %s [verbose level]\n", argv[0]);
- exit (1);
+
+ /* process argument */
+ while (argc-- > 1) {
+ char *arg = *(++argv);
+ if (arg[0] != '-') {
+ VERBOSE (mapec, ERROR, PRINTF ("%s: unknown command '%s'\n", progname, arg));
+ return 1;
+ }
+ char c = arg[1];
+ switch (c) {
+ case 'c':
+ arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
+ if (arg == NULL) {
+ VERBOSE (mapec, ERROR, PRINTF ("%s: client url not specified\n", progname));
+ return 1;
+ }
+ client_local_url = arg;
+ client_remote_url = ((argc > 1) && (**(argv + 1) != '-') && (argc--)) ? *(++argv) : NULL;
+ break;
+ case 's':
+ arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
+ if (arg == NULL) {
+ VERBOSE (mapec, ERROR, PRINTF ("%s: server url not specified\n", progname));
+ return 1;
+ }
+ server_local_url = arg;
+ server_remote_url = ((argc > 1) && (**(argv + 1) != '-') && (argc--)) ? *(++argv) : NULL;
+ 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 [-c url [url]] [-h] [-s url [url]] [-v int]\n", progname);
+ return (c != 'h');
+ }
}
printf ("*** STARTING SERVERS ***\n");
- pthread_t udp_thread;
+ pthread_t server_thread;
- pthread_create (&udp_thread, NULL, udp_server, NULL);
+ pthread_create (&server_thread, NULL, server, NULL);
/* Give some delay to server to setup there MAPEC */
usleep (1e6);
-
+
printf ("*** STARTING TEST SEQUENCE ***\n");
- pthread_t udp_client_thread;
+ pthread_t client_thread;
+
+ pthread_create (&client_thread, NULL, client, NULL);
- pthread_create (&udp_client_thread, NULL, udp_client, NULL);
+ pthread_join (client_thread, NULL);
- pthread_join (udp_client_thread, NULL);
-
printf ("*** END OF TEST SEQUENCE ***\n");
int failed = 0;
- DUMP_STATUS (MAPEC_Send_UDP_OK);
- DUMP_STATUS (MAPEC_Echo_UDP_OK);
+ DUMP_STATUS (MAPEC_Send_OK);
+ DUMP_STATUS (MAPEC_Echo_OK);
return failed ? EXIT_FAILURE : EXIT_SUCCESS;
}
+/* test: mapec_test.exe -h */
/* test: mapec_test.exe */
-/* test: mapec_test.exe 4 */
+/* test: mapec_test.exe -v 4 */
+/* test: mapec_test.exe -v 3 -c udp://localhost:1234 udp://localhost:1235 -s udp://localhost:1235 udp://localhost:1234 */
/* vim: set ts=4 sw=4 si et: */