--- /dev/null
+/*
+ File name : mapec.h
+ Projet : MERLIN
+ Date of creation : 2025/05/22
+ Version : 1.0
+ Copyright : Thales SIX
+ Author : Laurent Mazet <laurent.mazet@thalesgroup.com>
+
+ Description : Minimal API for Packet Exchange Commmunication
+
+ History :
+ - initial version
+*/
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "verbose.h"
+
+#include "mapec.h"
+
+DECLARE_VERBOSE_LEVEL (mapec, INFO);
+
+/**
+ MAPEC type
+*/
+typedef enum {
+ MAPEC_error_e = 0,
+ MAPEC_udp_e
+} MAPEC_type_t;
+
+/**
+ MAPEC address structure
+*/
+typedef struct {
+ MAPEC_type_t type;
+ struct sockaddr_in addrin;
+ struct sockaddr_in addrout;
+} MAPEC_addr_t;
+
+#define MAX_MAPEC_NUMBER 4096
+
+/**
+ List of private descriptor associated to each connected MAPEC.
+*/
+MAPEC_addr_t *MAPEC_list[MAX_MAPEC_NUMBER] = { 0 };
+
+MAPEC_addr_t *mapecdup (MAPEC_addr_t *mapec)
+{
+
+ VERBOSE (mapec, TRACE, PRINTF ("mapecdup\n"));
+
+ MAPEC_addr_t *newmapec = (MAPEC_addr_t *) calloc (1, sizeof (MAPEC_addr_t));
+ memcpy (newmapec, mapec, sizeof (MAPEC_addr_t));
+
+ return newmapec;
+}
+
+void free_all_mapecs (void)
+{
+
+ VERBOSE (mapec, TRACE, PRINTF ("free_mapecs\n"));
+
+ for (int i = 0; i < MAX_MAPEC_NUMBER; i++) {
+ free (MAPEC_list[i]);
+ MAPEC_list[i] = NULL;
+ }
+}
+
+void __attribute__ ((constructor)) _init_morep_ (void)
+{
+ atexit (free_all_mapecs);
+}
+
+int parse_protocol (MAPEC_addr_t *addr, char *url)
+{
+
+ VERBOSE (mapec, TRACE, PRINTF ("parse_protocol\n"));
+
+ int rc = -1;
+ MAPEC_type_t type = MAPEC_error_e;
+ if (strncmp (url, "udp://", 6) == 0) {
+ type = MAPEC_udp_e;
+ rc = 6;
+ }
+ if (addr->type == MAPEC_error_e) {
+ addr->type = type;
+ } else if (addr->type != type) {
+ rc = -1;
+ }
+
+ return rc;
+}
+
+
+int parse_address (struct sockaddr_in *addr, char *url)
+{
+
+ VERBOSE (mapec, TRACE, PRINTF ("parse_addr\n"));
+
+ char *pt = strchr (url, ':');
+ if (pt == NULL) {
+ VERBOSE (mapec, WARNING, PRINTF ("can't parse address '%s'\n", url));
+ return -1;
+ }
+
+ char *hostname = (char *) calloc (pt - url + 1, 1);
+ memcpy (hostname, url, pt - url);
+ char *port = pt + 1;
+ if ((*hostname == '\0') || (*port == '\0')) {
+ errno = EINVAL;
+ free (hostname);
+ return -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] != '*') {
+ struct hostent *he = gethostbyname (hostname);
+ if (he == NULL) {
+ errno = EHOSTUNREACH;
+ return -1;
+ }
+
+ struct in_addr **addr_list = (struct in_addr **) he->h_addr_list;
+ addr->sin_addr.s_addr = addr_list[0]->s_addr;
+ } else {
+ addr->sin_addr.s_addr = INADDR_ANY;
+ }
+ free (hostname);
+
+ return 0;
+}
+
+int MAPEC_Connect (char *local_address, char * remote_address)
+{
+
+ VERBOSE (mapec, TRACE, PRINTF ("MAPEC_Connect\n"));
+
+ MAPEC_addr_t mapec = { 0 };
+ int rc;
+
+ /* 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)) {
+ 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)));
+
+ /* 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)) {
+ 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)));
+
+ /* create socket */
+ int fid = socket (PF_INET, SOCK_DGRAM, 0);
+ if ((fid < 0) || (fid >= MAX_MAPEC_NUMBER) || (MAPEC_list[fid] != NULL)) {
+ VERBOSE (mapec, ERROR, PRINTF ("can't accept socket %d\n", fid));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* 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) {
+ 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) {
+ VERBOSE (mapec, ERROR, PRINTF ("can't connect socket %d\n", fid));
+ return -1;
+ }
+
+ MAPEC_list[fid] = mapecdup (&mapec);
+
+ return fid;
+}
+
+void MAPEC_Close (int fid)
+{
+
+ VERBOSE (mapec, TRACE, PRINTF ("MAPEC_Close\n"));
+
+ if ((fid < 0) || (fid >= MAX_MAPEC_NUMBER)) {
+ return;
+ }
+
+ close (fid);
+
+ free (MAPEC_list[fid]);
+ MAPEC_list[fid] = NULL;
+}
+
+int MAPEC_Send (int fid, unsigned char *data, int len)
+{
+
+ VERBOSE (mapec, TRACE, PRINTF ("MAPEC_Send\n"));
+
+ assert (((data != NULL) && (len > 0)) || ((data == NULL) && (len == 0)));
+
+ if ((fid < 0) || (fid >= MAX_MAPEC_NUMBER) || (MAPEC_list[fid] == NULL)) {
+ errno = EBADF;
+ return -1;
+ }
+
+ VERBOSE (mapec, DEBUG, PRINTF ("MAPEC_Send writting...\n"));
+
+ return write (fid, data, len);
+}
+
+int MAPEC_Receive_timeout (int fid, unsigned char *buffer, int maxlen, int ms)
+{
+
+ VERBOSE (mapec, TRACE, PRINTF ("MAPEC_Receive_timeout\n"));
+
+ fd_set rfds;
+ struct timeval tv = { 0, ms };
+ FD_ZERO (&rfds);
+ FD_SET (fid, &rfds);
+
+ int retval = select (fid + 1, &rfds, NULL, NULL, &tv);
+ if (retval != 1) {
+ return retval;
+ }
+
+ return MAPEC_Receive (fid, buffer, maxlen);
+}
+
+int MAPEC_Receive (int fid, unsigned char *buffer, int maxlen)
+{
+
+ VERBOSE (mapec, TRACE, PRINTF ("MAPEC_Receive\n"));
+
+ if ((fid < 0) || (fid >= MAX_MAPEC_NUMBER) || (MAPEC_list[fid] == NULL)) {
+ errno = EBADF;
+ return -1;
+ }
+
+ VERBOSE (mapec, DEBUG, PRINTF ("MAPEC_Receive reading...\n"));
+
+ int rc = read (fid, buffer, maxlen);
+
+ if ((rc < 0) && (errno == EAGAIN)) {
+ rc = 0;
+ }
+
+ return rc;
+}
+
+/* vim: set ts=4 sw=4 si et: */
--- /dev/null
+/*
+ File name : mapec.h
+ Projet : MERLIN
+ Date of creation : 2025/05/22
+ Version : 1.0
+ Copyright : Thales SIX
+ Author : Laurent Mazet <laurent.mazet@thalesgroup.com>
+
+ Description : Minimal API for Packet Exchange Commmunication
+
+ History :
+ - initial version
+*/
+
+#ifndef __MAPEC_H__
+#define __MAPEC_H__
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ @defgroup MAPEC Public API of MAPEC
+
+ This library offers connections over UDP socket or TUN interface. In
+ both case, communication is based on packet exchanges.
+
+ Values returned by MAPEC_Connect are standard Linux file descriptors
+ that can be used in select()/poll() system calls.
+*/
+
+/**
+ @ingroup MAPEC
+
+ 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.
+
+ @return a new file descriptor associated with this connection
+
+ @see MAPEC_Close()
+ @see MAPEC_Send()
+ @see MAPEC_Receive()
+*/
+int MAPEC_Connect (char *local_address, char *remote_address);
+
+/**
+ @ingroup MAPEC
+
+ Destroy a MAPEC.
+
+ @param fid the file descriptor retuned by MAPEC_Connect()
+
+ @see MAPEC_Connect()
+*/
+void MAPEC_Close (int fid);
+
+/**
+ @ingroup MAPEC
+
+ Send a message over an existing MAPEC connection. Will block until
+ resolution in case of congestion.
+
+ @param fid the file descriptor retuned by MAPEC_Connect()
+ @param data a pointer to the buffer containing the message to be
+ transmitted
+ @param len length of the message
+
+ @return 0 on success, -1 on error
+
+ @see MAPEC_Connect()
+*/
+int MAPEC_Send (int fid, unsigned char *data, int len);
+
+/**
+ @ingroup MAPEC
+
+ Received a message over an existing MAPEC connection.
+
+ @param fid the file descriptor retuned by MAPEC_Connect()
+ @param buffer a pointer to the reception buffer
+ @param maxlen maximum length of the reception buffer
+
+ @return length of the message or -1 on error
+
+ @see MAPEC_Connect()
+*/
+int MAPEC_Receive (int sap, unsigned char *buffer, int maxlen);
+
+/**
+ @ingroup MAPEC
+
+ Received a message over an existing MAPEC connection with a timeout
+
+ @param sap the file descriptor retuned by MAPEC_Connect()
+ @param buffer a pointer to the reception buffer
+ @param maxlen max length of the reception buffer
+ @param ms exit after x microseconds if no data is received
+
+ @return length of the message or -1 on error
+
+ @see MAPEC_Connect()
+*/
+int MAPEC_Receive_timeout (int sap, unsigned char *buffer, int maxlen, int ms);
+
+__END_DECLS
+
+#endif /* __MAPEC_H__ */
+
+/* vim: set ts=4 sw=4 si et: */
--- /dev/null
+/*
+ File name : mapec_test.c
+ Projet : MERLIN
+ Date of creation : 2025/05/22
+ Version : 1.0
+ Copyright : Thales SIX
+ Author : Laurent Mazet <laurent.mazet@thalesgroup.com>
+
+ Description : Test program for MAPEC socket
+
+ History :
+ - initial version
+*/
+
+/* depend: */
+/* cflags: */
+/* linker: mapec.o */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <pthread.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "verbose.h"
+
+#include "mapec.h"
+
+int MAPEC_Send_UDP_OK = 0;
+int MAPEC_Echo_UDP_OK = 0;
+
+#define UNUSED __attribute__ ((unused))
+
+void *udp_client (UNUSED void *dummy)
+{
+
+ VERBOSE (mapec, TRACE, PRINTF ("test_client\n"));
+
+ int count;
+ unsigned char tx_data[10][1500];
+ int tx_len[10];
+
+ int fid = MAPEC_Connect ("udp://localhost:13501", "udp://localhost:12501");
+ if (fid < 0) {
+ VERBOSE (mapec, WARNING, PRINTF ("client MAPEC_Connect error\n"));
+ MAPEC_Echo_UDP_OK = 0;
+ return NULL;
+ }
+
+ int nb_messages = 10;
+ 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;
+ 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;
+ return NULL;
+ }
+ VERBOSE (mapec, DEBUG, PRINTF ("client MAPEC_Send ok (%d)\n", tx_len[count]));
+
+ usleep (1e4);
+
+ int rx_len;
+ unsigned char rx_data[32768];
+
+ do {
+ rx_len = MAPEC_Receive (fid, rx_data, sizeof (rx_data));
+ if (rx_len == 0) {
+ VERBOSE (mapec, DEBUG, PRINTF ("client's sleeping...\n"));
+ usleep (1e3);
+ }
+ } while (rx_len == 0);
+
+ VERBOSE (mapec, INFO, PRINTF ("client received echo count=%d len=%d, fid=%d\n", count, rx_len, fid));
+
+ 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;
+ 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;
+ return NULL;
+ }
+ }
+
+ MAPEC_Close (fid);
+ VERBOSE (mapec, INFO, PRINTF ("client end of test, %d echo processed\n", count));
+ MAPEC_Echo_UDP_OK = 1;
+
+ return NULL;
+}
+
+void *udp_server (UNUSED void *dummy)
+{
+
+ VERBOSE (mapec, TRACE, PRINTF ("udp_server\n"));
+
+ int fid = MAPEC_Connect ("udp://localhost:12501", "udp://localhost:13501");
+ if (fid < 0) {
+ VERBOSE (mapec, ERROR, PRINTF ("MAPEC_Connect (%d)", fid));
+ exit (1);
+ }
+
+ VERBOSE (mapec, INFO, PRINTF ("udp_server waiting for data\n"));
+
+ while (1) {
+ unsigned char data[8192];
+
+ int rx_len = MAPEC_Receive (fid, data, sizeof (data));
+ if (rx_len == 0) {
+ VERBOSE (mapec, DEBUG, PRINTF ("server's sleeping...\n"));
+ usleep (1e3);
+ continue;
+ }
+ if (rx_len < 0) {
+ VERBOSE (mapec, ERROR, PRINTF ("error receiving from MAPEC %d\n", fid));
+ MAPEC_Close (fid);
+ break;
+ }
+
+ VERBOSE (mapec, INFO, PRINTF ("udp_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;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Dump status macro
+*/
+#define DUMP_STATUS(x) do { \
+ printf (#x " %s\n", (x) ? "OK" : "BAD"); \
+ if (!(x)) { \
+ failed = 1; \
+ } \
+ } while (0) \
+
+int main (int argc, char **argv)
+{
+
+ /* process arguments */
+ if (argc > 1) {
+ CHANGE_VERBOSE_LEVEL (mapec, atoi (argv[1]));
+ argc--;
+ }
+ if (argc > 1) {
+ printf ("usage: %s [verbose level]\n", argv[0]);
+ exit (1);
+ }
+
+ printf ("*** STARTING SERVERS ***\n");
+
+ pthread_t udp_thread;
+
+ pthread_create (&udp_thread, NULL, udp_server, NULL);
+
+ /* Give some delay to server to setup there MAPEC */
+ usleep (1e6);
+
+ printf ("*** STARTING TEST SEQUENCE ***\n");
+
+ pthread_t udp_client_thread;
+
+ pthread_create (&udp_client_thread, NULL, udp_client, 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);
+
+ return failed ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+/* test: mapec_test.exe */
+/* test: mapec_test.exe 4 */
+
+/* vim: set ts=4 sw=4 si et: */
+++ /dev/null
-/*
- Service Access Point communication library
-
- Copyrigth Eichos 20100319
-*/
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#if WIN32
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#define OPT_TYPE char
-#else /* Linux */
-#include <netdb.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <sys/select.h>
-#include <sys/socket.h>
-#define OPT_TYPE int
-#endif
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-//#include "tools.h"
-#include "verbose.h"
-
-#include "sap.h"
-
-DECLARE_VERBOSE_LEVEL (sap, INFO);
-
-/**
- SAP type
-*/
-typedef enum {
- SAP_error_e = 0,
- SAP_udp_e
-} SAP_type_t;
-
-/**
- SAP address structure
-*/
-typedef struct {
- SAP_type_t type;
- struct sockaddr_in addrin;
- struct sockaddr_in addrout;
-} SAP_addr_t;
-
-#define MAX_SAP_NUMBER 4096
-
-/**
- List of private descriptor associated to each connected SAP.
-*/
-SAP_addr_t *SAP_list[MAX_SAP_NUMBER] = { 0 };
-
-SAP_addr_t *sapdup (SAP_addr_t *sap)
-{
-
- VERBOSE (sap, TRACE, PRINTF ("sapdup\n"));
-
- SAP_addr_t *newsap = (SAP_addr_t *) calloc (1, sizeof (SAP_addr_t));
- memcpy (newsap, sap, sizeof (SAP_addr_t));
-
- return newsap;
-}
-
-void free_all_saps (void)
-{
-
- VERBOSE (sap, TRACE, PRINTF ("free_saps\n"));
-
- for (int i = 0; i < MAX_SAP_NUMBER; i++) {
- free (SAP_list[i]);
- SAP_list[i] = NULL;
- }
-}
-
-void __attribute__ ((constructor)) _init_morep_ (void)
-{
- atexit (free_all_saps);
-}
-
-int parse_protocol (SAP_addr_t *addr, char *url)
-{
-
- VERBOSE (sap, TRACE, PRINTF ("parse_protocol\n"));
-
- int rc = -1;
- SAP_type_t type = SAP_error_e;
- if (strncmp (url, "udp://", 6) == 0) {
- type = SAP_udp_e;
- rc = 6;
- }
- if (addr->type == SAP_error_e) {
- addr->type = type;
- } else if (addr->type != type) {
- rc = -1;
- }
-
- return rc;
-}
-
-
-int parse_address (struct sockaddr_in *addr, char *url)
-{
-
- VERBOSE (sap, TRACE, PRINTF ("parse_addr\n"));
-
- char *pt = strchr (url, ':');
- if (pt == NULL) {
- VERBOSE (sap, WARNING, PRINTF ("can't parse address '%s'\n", url));
- return -1;
- }
-
- char *hostname = (char *) calloc (pt - url + 1, 1);
- memcpy (hostname, url, pt - url);
- char *port = pt + 1;
- if ((*hostname == '\0') || (*port == '\0')) {
- errno = EINVAL;
- free (hostname);
- return -1;
- }
-
- addr->sin_family = AF_INET;
- addr->sin_port = htons (atoi (port));
-
- VERBOSE (sap, INFO, PRINTF ("parse URL -> %s %s\n", hostname, port));
-
- if (hostname[0] != '*') {
- struct hostent *he = gethostbyname (hostname);
- if (he == NULL) {
- errno = EHOSTUNREACH;
- return -1;
- }
-
- struct in_addr **addr_list = (struct in_addr **) he->h_addr_list;
- addr->sin_addr.s_addr = addr_list[0]->s_addr;
- } else {
- addr->sin_addr.s_addr = INADDR_ANY;
- }
- free (hostname);
-
- return 0;
-}
-
-int SAP_Connect (char *local_address, char * remote_address)
-{
-
- VERBOSE (sap, TRACE, PRINTF ("SAP_Connect\n"));
-
- SAP_addr_t sap = { 0 };
- int rc;
-
- /* parse local url */
- VERBOSE (sap, DEBUG, PRINTF ("SAP local addr %s\n", local_address));
- rc = parse_protocol (&sap, local_address);
- if ((rc <= 0) || (parse_address (&sap.addrin, local_address + rc) < 0)) {
- VERBOSE (sap, ERROR, PRINTF ("can't parse local url\n"));
- errno = EINVAL;
- return -1;
- }
- VERBOSE (sap, DEBUG, PRINTF ("local port -> %d\n", ntohs (sap.addrin.sin_port)));
-
- /* parse remote url */
- VERBOSE (sap, DEBUG, PRINTF ("SAP remote addr %s\n", remote_address));
- rc = parse_protocol (&sap, remote_address);
- if ((rc <= 0) || (parse_address (&sap.addrout, remote_address + rc) < 0)) {
- VERBOSE (sap, ERROR, PRINTF ("can't parse remote url\n"));
- errno = EINVAL;
- return -1;
- }
- VERBOSE (sap, DEBUG, PRINTF ("remote port -> %d\n", ntohs (sap.addrout.sin_port)));
-
- /* create socket */
- int sock = socket (PF_INET, SOCK_DGRAM, 0);
- if ((sock < 0) || (sock >= MAX_SAP_NUMBER) || (SAP_list[sock] != NULL)) {
- VERBOSE (sap, ERROR, PRINTF ("can't accept socket %d\n", sock));
- errno = ENOMEM;
- return -1;
- }
-
- /* bind on local */
- int val = 1;
- setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (OPT_TYPE *)&val, sizeof (val));
- if (bind (sock, (struct sockaddr *)&sap.addrin, sizeof (sap.addrin)) < 0) {
- VERBOSE (sap, ERROR, PRINTF ("can't bind socket %d\n", sock));
- return -1;
- }
-
- /* connect on remote */
- if (connect (sock, (struct sockaddr *)&sap.addrout, sizeof (sap.addrout)) < 0) {
- VERBOSE (sap, ERROR, PRINTF ("can't connect socket %d\n", sock));
- return -1;
- }
-
- SAP_list[sock] = sapdup (&sap);
-
- return sock;
-}
-
-void SAP_Close (int sap)
-{
-
- VERBOSE (sap, TRACE, PRINTF ("SAP_Close\n"));
-
- if ((sap < 0) || (sap >= MAX_SAP_NUMBER)) {
- return;
- }
-
- close (sap);
-
- free (SAP_list[sap]);
- SAP_list[sap] = NULL;
-}
-
-int SAP_Send (int sap, unsigned char *data, int len)
-{
-
- VERBOSE (sap, TRACE, PRINTF ("SAP_Send\n"));
-
- assert (((data != NULL) && (len > 0)) || ((data == NULL) && (len == 0)));
-
- if ((sap < 0) || (sap >= MAX_SAP_NUMBER) || (SAP_list[sap] == NULL)) {
- errno = EBADF;
- return -1;
- }
-
- VERBOSE (sap, TRACE, PRINTF ("SAP_Send writting...\n"));
-
- return write (sap, data, len);
-}
-
-int SAP_Receive_timeout (int sap, unsigned char *buffer, int maxlen, int ms)
-{
-
- VERBOSE (sap, TRACE, PRINTF ("SAP_Receive_timeout\n"));
-
- fd_set rfds;
- struct timeval tv = { 0, ms };
- FD_ZERO (&rfds);
- FD_SET (sap, &rfds);
-
- int retval = select (sap + 1, &rfds, NULL, NULL, &tv);
- if (retval != 1) {
- return retval;
- }
-
- return SAP_Receive (sap, buffer, maxlen);
-}
-
-int SAP_Receive (int sap, unsigned char *buffer, int maxlen)
-{
-
- VERBOSE (sap, TRACE, PRINTF ("SAP_Receive\n"));
-
- if ((sap < 0) || (sap >= MAX_SAP_NUMBER) || (SAP_list[sap] == NULL)) {
- errno = EBADF;
- return -1;
- }
-
- VERBOSE (sap, TRACE, PRINTF ("SAP_Receive reading...\n"));
-
- int rc = read (sap, buffer, maxlen);
-
- if ((rc < 0) && (errno == EAGAIN)) {
- rc = 0;
- }
-
- return rc;
-}
-
-/* vim: set ts=4 sw=4 si et: */
+++ /dev/null
-/*
- Service Access Point communication library
-
- Copyrigth Eichos 20100319
-*/
-
-#ifndef __SAP_H__
-#define __SAP_H__
-
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-
-/**
- @defgroup SAP Public API of SAP
-
- The common message passing library offers both reliable and
- unreliable connection oriented data blocks exchange service between
- software modules running on separate CPU. The current
- implementation is based on TCP (reliable) and UDP (unreliable),
- however, the abstraction level provided by this library will permit
- future implementations on other communication networks (shared
- memory for example).
-
- sap values returned by SAP_Connect is a standard Linux file
- descriptors that can be used in select()/poll() system calls.
-*/
-
-/**
- @ingroup SAP
-
- Establish a connection between a local SAP and a remote SAP. Block
- until connection is established or refused.
-
- @param local_address local address of the SAP with the following
- syntax: 'udp://hostname:port'.
- @param remote_address same format as for local_address
-
- @return a new file descriptor associated with this connection
-
- @see SAP_Close()
- @see SAP_Send()
- @see SAP_Receive()
-*/
-int SAP_Connect (char *local_address, char *remote_address);
-
-/**
- @ingroup SAP
-
- Destroy a SAP.
-
- @param sap the file descriptor retuned by SAP_Connect()
-
- @see SAP_Connect()
-*/
-void SAP_Close (int sap);
-
-/**
- @ingroup SAP
-
- Send a message over an existing SAP connection. Will block until
- resolution in case of congestion.
-
- @param sap the file descriptor retuned by SAP_Connect() or
- SAP_Accept()
- @param data a pointer to the buffer containing the message to be
- transmitted
- @param len length of the message
-
- @see SAP_Connect()
-*/
-int SAP_Send (int sap, unsigned char *data, int len);
-
-/**
- @ingroup SAP
-
- Received a message over an existing SAP connection. Returns
- immediately if SAP not set to blocking mode
-
- @param sap the file descriptor retuned by SAP_Connect()
- @param buffer a pointer to the reception buffer
- @param maxlen max length of the reception buffer
-
- @return length of the message or 0 if no message was pending
-
- @see SAP_Connect()
-*/
-int SAP_Receive (int sap, unsigned char *buffer, int maxlen);
-
-/**
- @ingroup SAP
-
- Received a message over an existing SAP connection with a timeout
-
- @param sap the file descriptor retuned by SAP_Connect()
- @param buffer a pointer to the reception buffer
- @param maxlen max length of the reception buffer
- @param ms Exit after microseconds if now data is received
-
- @return length of the message or 0 if no message was pending
-
- @see SAP_Connect()
-*/
-int SAP_Receive_timeout (int sap, unsigned char *buffer, int maxlen, int ms);
-
-__END_DECLS
-
-#endif /* __SAP_H__ */
-
-/* vim: set ts=4 sw=4 si et: */
+++ /dev/null
-/*
- File: sap_valid.c
- Author: Laurent Mazet <mazet@eichos.com>
-
- Validation test suite for SAP library
-
- Copyrigth Eichos 20100322
-*/
-
-/* depend: */
-/* cflags: */
-/* linker: sap.o */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <assert.h>
-#include <pthread.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "verbose.h"
-
-#include "sap.h"
-
-int SAP_Send_UDP_OK = 0;
-int SAP_Echo_UDP_OK = 0;
-
-#define UNUSED __attribute__ ((unused))
-
-void *udp_client (UNUSED void *dummy)
-{
-
- VERBOSE (sap, TRACE, PRINTF ("test_client\n"));
-
- int count;
- unsigned char tx_data[10][1500];
- int tx_len[10];
-
- int sap = SAP_Connect ("udp://localhost:13501", "udp://localhost:12501");
- if (sap < 0) {
- VERBOSE (sap, WARNING, PRINTF ("client SAP_Connect error\n"));
- SAP_Echo_UDP_OK = 0;
- return NULL;
- }
-
- int nb_messages = 10;
- VERBOSE (sap, 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 = SAP_Send (sap, tx_data[count], tx_len[count]);
- if (rc < 0) {
- VERBOSE (sap, WARNING, PRINTF ("client SAP_Send tx error (%d/%d-%d)\n", rc, tx_len[count], errno));
- SAP_Echo_UDP_OK = 0;
- return NULL;
- }
-
- if (tx_len[count] != rc) {
- VERBOSE (sap, WARNING, PRINTF ("client SAP_Send tx len error tx=%d rc=%d\n", tx_len[count], rc));
- SAP_Echo_UDP_OK = 0;
- return NULL;
- }
- VERBOSE (sap, DEBUG, PRINTF ("client SAP_Send ok (%d)\n", tx_len[count]));
-
- usleep (1e4);
-
- int rx_len;
- unsigned char rx_data[32768];
-
- do {
- rx_len = SAP_Receive (sap, rx_data, sizeof (rx_data));
- if (rx_len == 0) {
- VERBOSE (sap, DEBUG, PRINTF ("client's sleeping...\n"));
- usleep (1e3);
- }
- } while (rx_len == 0);
-
- VERBOSE (sap, INFO, PRINTF ("client received echo count=%d len=%d, sap=%d\n", count, rx_len, sap));
-
- if (tx_len[count] != rx_len) {
- VERBOSE (sap, WARNING, PRINTF ("client SAP_Receive rx len error : tx=%d / rx=%d\n", tx_len[count], rx_len));
- SAP_Echo_UDP_OK = 0;
- return NULL;
- }
-
- if (memcmp (rx_data, tx_data[count], tx_len[count]) != 0 ) {
- VERBOSE (sap, WARNING, PRINTF ("client SAP_Receive rx corrupted data\n"));
- SAP_Echo_UDP_OK = 0;
- return NULL;
- }
- }
-
- SAP_Close (sap);
- VERBOSE (sap, INFO, PRINTF ("client end of test, %d echo processed\n", count));
- SAP_Echo_UDP_OK = 1;
-
- return NULL;
-}
-
-void *udp_server (UNUSED void *dummy)
-{
-
- VERBOSE (sap, TRACE, PRINTF ("udp_server\n"));
-
- int sap = SAP_Connect ("udp://localhost:12501", "udp://localhost:13501");
- if (sap < 0) {
- VERBOSE (sap, ERROR, PRINTF ("SAP_Connect (%d)", sap));
- exit (1);
- }
-
- VERBOSE (sap, INFO, PRINTF ("udp_server waiting for data\n"));
-
- while (1) {
- unsigned char data[8192];
-
- int rx_len = SAP_Receive (sap, data, sizeof (data));
- if (rx_len == 0) {
- VERBOSE (sap, DEBUG, PRINTF ("server's sleeping...\n"));
- usleep (1e3);
- continue;
- }
- if (rx_len < 0) {
- VERBOSE (sap, ERROR, PRINTF ("error receiving from SAP %d\n", sap));
- SAP_Close (sap);
- break;
- }
-
- VERBOSE (sap, INFO, PRINTF ("udp_server receive data len=%d, sending echo\n", rx_len));
- usleep (1e4);
-
- int tx_len = SAP_Send (sap, data, rx_len);
- if (tx_len == rx_len) {
- SAP_Send_UDP_OK = 1;
- }
- }
-
- return NULL;
-}
-
-/**
- Dump status macro
-*/
-#define DUMP_STATUS(x) do { \
- printf (#x " %s\n", (x) ? "OK" : "BAD"); \
- if (!(x)) { \
- failed = 1; \
- } \
- } while (0) \
-
-int main (int argc, char **argv)
-{
-
- /* process arguments */
- if (argc > 1) {
- CHANGE_VERBOSE_LEVEL(sap, atoi (argv[1]));
- argc--;
- }
- if (argc > 1) {
- printf ("usage: %s [verbose level]\n", argv[0]);
- exit (1);
- }
-
- printf ("*** STARTING SERVERS ***\n");
-
- pthread_t udp_thread;
-
- pthread_create (&udp_thread, NULL, udp_server, NULL);
-
- /* Give some delay to server to setup there SAP */
- usleep (1e6);
-
- printf ("*** STARTING TEST SEQUENCE ***\n");
-
- pthread_t udp_client_thread;
-
- pthread_create (&udp_client_thread, NULL, udp_client, NULL);
-
- pthread_join (udp_client_thread, NULL);
-
- printf ("*** END OF TEST SEQUENCE ***\n");
-
- int failed = 0;
- DUMP_STATUS (SAP_Send_UDP_OK);
- DUMP_STATUS (SAP_Echo_UDP_OK);
-
- return failed ? EXIT_FAILURE : EXIT_SUCCESS;
-}
-
-/* test: sap_test.exe */
-/* test: sap_test.exe 1 */
-
-/* vim: set ts=4 sw=4 si et: */