DECLARE_VERBOSE_LEVEL (sap, INFO);
+/**
+ SAP type
+*/
+typedef enum {
+ SAP_error_e = 0,
+ SAP_udp_e
+} SAP_type_t;
+
/**
SAP address structure
*/
typedef struct {
- enum { SAP_error, SAP_udp } type;
- struct sockaddr_in sockaddr;
+ SAP_type_t type;
+ struct sockaddr_in addrin;
+ struct sockaddr_in addrout;
} SAP_addr_t;
#define MAX_SAP_NUMBER 4096
-/**
- Type of private descriptor associated to each connected SAP.
-*/
-typedef struct {
- int is_blocking;
-} SAP_descriptor_t ;
-
/**
List of private descriptor associated to each connected SAP.
*/
-SAP_descriptor_t *SAP_list[MAX_SAP_NUMBER] = { 0 };
+SAP_addr_t *SAP_list[MAX_SAP_NUMBER] = { 0 };
-/**
- Init flag
-*/
-static int __init = 1;
+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_saps (void)
+void free_all_saps (void)
{
VERBOSE (sap, TRACE, PRINTF ("free_saps\n"));
}
}
-static inline int parse_url (const char *ascii_url, SAP_addr_t *addr)
+void __attribute__ ((constructor)) _init_morep_ (void)
{
+ atexit (free_all_saps);
+}
- VERBOSE (sap, TRACE, PRINTF ("parse_url\n"));
+int parse_protocol (SAP_addr_t *addr, char *url)
+{
- struct in_addr **addr_list;
- char url_to_parse[256] = { 0 };
+ VERBOSE (sap, TRACE, PRINTF ("parse_protocol\n"));
- strncpy (url_to_parse, ascii_url, sizeof (url_to_parse) - 1);
- if (strncmp (url_to_parse, "udp://", 6) == 0) {
- addr->type = SAP_udp;
- } else {
+ 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 = strtok (url_to_parse + 6, ":");
- char *port = strtok (NULL, ":");
- if ((hostname == NULL) || (port == NULL)) {
+ 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->sockaddr.sin_family = AF_INET;
- addr->sockaddr.sin_port = htons (atoi (port));
+ addr->sin_family = AF_INET;
+ addr->sin_port = htons (atoi (port));
- VERBOSE (sap, INFO, PRINTF ("parse URL %s %s\n", hostname, port));
+ VERBOSE (sap, INFO, PRINTF ("parse URL -> %s %s\n", hostname, port));
if (hostname[0] != '*') {
struct hostent *he = gethostbyname (hostname);
return -1;
}
- addr_list = (struct in_addr **) he->h_addr_list;
- addr->sockaddr.sin_addr.s_addr = addr_list[0]->s_addr;
+ struct in_addr **addr_list = (struct in_addr **) he->h_addr_list;
+ addr->sin_addr.s_addr = addr_list[0]->s_addr;
} else {
- addr->sockaddr.sin_addr.s_addr = INADDR_ANY;
+ addr->sin_addr.s_addr = INADDR_ANY;
}
+ free (hostname);
return 0;
}
-static inline int sap_create_and_listen (char *local_address)
+int SAP_Connect (char *local_address, char * remote_address)
{
- VERBOSE (sap, TRACE, PRINTF ("sap_create_and_listen\n"));
+ VERBOSE (sap, TRACE, PRINTF ("SAP_Connect\n"));
- SAP_addr_t addr;
- int sap = 0;
+ SAP_addr_t sap = { 0 };
+ int rc;
+ /* parse local url */
VERBOSE (sap, DEBUG, PRINTF ("SAP local addr %s\n", local_address));
- if (parse_url (local_address, &addr) < 0) {
- VERBOSE (sap, ERROR, PRINTF ("can't parse url\n"));
- errno = EINVAL;
- return -1;
- }
-
- VERBOSE (sap, DEBUG, PRINTF ("local port: %d\n", ntohs (addr.sockaddr.sin_port)));
-
- switch (addr.type) {
- case SAP_udp:
- sap = socket (PF_INET, SOCK_DGRAM, 0);
- if (sap >= 0) {
- int val = 1;
- setsockopt (sap, SOL_SOCKET, SO_REUSEADDR, (OPT_TYPE *)&val, sizeof (val));
- if (bind (sap, (struct sockaddr *)&addr.sockaddr, sizeof (addr.sockaddr)) < 0) {
- VERBOSE (sap, ERROR, PRINTF ("cant bind on SAP %d\n", sap));
- }
- }
- break;
- default:
+ 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;
- break;
}
+ VERBOSE (sap, DEBUG, PRINTF ("local port -> %d\n", ntohs (sap.addrin.sin_port)));
- return sap;
-}
-
-int SAP_Create (char *local_address)
-{
-
- VERBOSE (sap, TRACE, PRINTF ("SAP_Create\n"));
-
- return sap_create_and_listen (local_address);
-}
-
-int SAP_Connect (char *local_address, char * remote_address)
-{
-
- VERBOSE (sap, TRACE, PRINTF ("SAP_Connect\n"));
-
- SAP_addr_t addr;
- int sap;
-
+ /* parse remote url */
VERBOSE (sap, DEBUG, PRINTF ("SAP remote addr %s\n", remote_address));
- if (parse_url (remote_address, &addr) < 0) {
- VERBOSE (sap, ERROR, PRINTF ("can't parse url\n"));
+ 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)));
- VERBOSE (sap, DEBUG, PRINTF ("remote port: %d\n", ntohs (addr.sockaddr.sin_port)));
-
- if (local_address) {
- VERBOSE (sap, DEBUG, PRINTF ("SAP local addr %s\n", local_address));
- sap = sap_create_and_listen (local_address);
- } else {
- VERBOSE (sap, DEBUG, PRINTF ("SAP local addr '*'\n"));
- switch (addr.type) {
- case SAP_udp:
- sap = socket (PF_INET, SOCK_DGRAM, 0);
- break;
- default:
- VERBOSE (sap, ERROR, PRINTF ("unkown protocol\n"));
- errno = EINVAL;
- return -1;
- }
- }
-
- if (sap < 0) {
- VERBOSE (sap, ERROR, PRINTF ("can't accept any SAP\n"));
- return sap;
- }
- if (sap >= MAX_SAP_NUMBER) {
- VERBOSE (sap, ERROR, PRINTF ("no more SAP avaliable\n"));
+ /* 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;
}
- if (connect (sap, (struct sockaddr *)&addr.sockaddr, sizeof (addr.sockaddr)) < 0) {
- VERBOSE (sap, ERROR, PRINTF ("can't connect on soket %d\n", sap));
+ /* 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;
}
-
- assert (SAP_list[sap] == NULL);
- SAP_list[sap] = (SAP_descriptor_t *) calloc (1, sizeof (SAP_descriptor_t));
- assert (SAP_list[sap]);
-
- if (__sync_bool_compare_and_swap (&__init, 1, 0)) {
- atexit (free_saps);
- }
-
- return sap;
-}
-
-int SAP_IsConnected (int sap)
-{
-
- VERBOSE (sap, TRACE, PRINTF ("SAP_IsConnected\n"));
- int sockerr;
- socklen_t rlen = sizeof (sockerr);
-
- if (getsockopt (sap, SOL_SOCKET, SO_ERROR, (OPT_TYPE *)&sockerr, &rlen) < 0) {
- VERBOSE (sap, ERROR, PRINTF ("error on getsockopt\n"));
+ /* 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);
- switch (sockerr) {
- case 0:
- return 1;
- break;
- case EINPROGRESS:
- return 0;
- break;
- }
-
- return -1;
-}
-
-void SAP_Reject (int sap)
-{
-
- VERBOSE (sap, TRACE, PRINTF ("SAP_Reject\n"));
-
- int newsap = accept (sap, NULL, 0);
- close (newsap);
+ return sock;
}
void SAP_Close (int sap)
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_Create(), SAP_Connect and
- SAP_Accept() are standard Linux file descriptors that can be used
- in select()/poll() system calls.
-*/
-
-/**
- @ingroup SAP
-
- Create a new SAP (Service Access Point) that will be used later for
- outgoing or incoming connection
- @param local_address local address of the SAP with the following
- syntax: 'udp://hostname:port' or 'tcp://hostname:port', hostname
- can be '*' to listen on any address handled by the host
-
- @return a new file descriptor associated with this SAP
-
- @see SAP_Connect()
- @see SAP_Accept()
- @see SAP_Reject()
- @see SAP_Close()
+ sap values returned by SAP_Connect is a standard Linux file
+ descriptors that can be used in select()/poll() system calls.
*/
-int SAP_Create (char *local_address);
/**
@ingroup SAP
until connection is established or refused.
@param local_address local address of the SAP with the following
- syntax: 'udp://hostname:port' or 'tcp://hostname:port'. Can be
- NULL if local address dot not need to be specified
+ syntax: 'udp://hostname:port'.
@param remote_address same format as for local_address
@return a new file descriptor associated with this connection
- @see SAP_Create()
- @see SAP_Accept()
- @see SAP_Reject()
@see SAP_Close()
@see SAP_Send()
@see SAP_Receive()
*/
int SAP_Connect (char *local_address, char *remote_address);
-/**
- @ingroup SAP
-
- Check if connection is established, typ. called after
- SAP_Connect()
-
- @param sap sap retuned by SAP_Connect
-
- @return -1=error, 0=not yet connected, 1=connected
-
- @see SAP_Connect()
-*/
-int SAP_Is_Connected (int sap);
-
-/**
- @ingroup SAP
-
- Reject an incoming connection. Returns immediately.
-
- @param sap the file descriptor retuned by SAP_Create()
-
- @see SAP_Create()
- @see SAP_Accept()
- @see SAP_Close()
- @see SAP_Send()
- @see SAP_Receive()
-*/
-void SAP_Reject (int sap);
-
/**
@ingroup SAP
Destroy a SAP.
- @param sap the file descriptor retuned by SAP_Create() or
- SAP_Connect() or SAP_Accept()
+ @param sap the file descriptor retuned by SAP_Connect()
- @see SAP_Create()
- @see SAP_Accept()
@see SAP_Connect()
*/
void SAP_Close (int sap);
transmitted
@param len length of the message
- @see SAP_Accept()
@see SAP_Connect()
*/
int SAP_Send (int sap, unsigned char *data, int len);
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() or
- SAP_Accept()
+ @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_Accept()
@see SAP_Connect()
*/
int SAP_Receive (int sap, unsigned char *buffer, int maxlen);
Received a message over an existing SAP connection with a timeout
- @param sap the file descriptor retuned by SAP_Connect() or
- SAP_Accept()
+ @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_Accept()
@see SAP_Connect()
*/
int SAP_Receive_timeout (int sap, unsigned char *buffer, int maxlen, int ms);
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;
- }
+ tx_len[count] = rand () % sizeof (tx_data[count]);
+ for (int i = 0; i < tx_len[count]; i++)
+ tx_data[count][i] = rand () % 256;
- 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]));
- }
+ 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);
- for (count = 0; count < 10; count++) {
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"));
- sleep (1);
+ usleep (1e3);
}
} while (rx_len == 0);
int rx_len = SAP_Receive (sap, data, sizeof (data));
if (rx_len == 0) {
VERBOSE (sap, DEBUG, PRINTF ("server's sleeping...\n"));
- sleep (1);
+ usleep (1e3);
continue;
}
if (rx_len < 0) {
}
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) {
pthread_create (&udp_thread, NULL, udp_server, NULL);
/* Give some delay to server to setup there SAP */
- sleep (1);
+ usleep (1e6);
printf ("*** STARTING TEST SEQUENCE ***\n");