summaryrefslogtreecommitdiff
path: root/util_ack
diff options
context:
space:
mode:
Diffstat (limited to 'util_ack')
-rw-r--r--util_ack/Makefile33
-rw-r--r--util_ack/readme.md65
-rw-r--r--util_ack/src/util_ack.c193
3 files changed, 291 insertions, 0 deletions
diff --git a/util_ack/Makefile b/util_ack/Makefile
new file mode 100644
index 0000000..4990099
--- /dev/null
+++ b/util_ack/Makefile
@@ -0,0 +1,33 @@
+### Application-specific constants
+
+APP_NAME := util_ack
+
+### Constant symbols
+
+CC := $(CROSS_COMPILE)gcc
+AR := $(CROSS_COMPILE)ar
+
+CFLAGS := -O2 -Wall -Wextra -std=c99 -Iinc -I.
+
+OBJDIR = obj
+
+### General build targets
+
+all: $(APP_NAME)
+
+clean:
+ rm -f $(OBJDIR)/*.o
+ rm -f $(APP_NAME)
+
+### Main program compilation and assembly
+
+$(OBJDIR):
+ mkdir -p $(OBJDIR)
+
+$(OBJDIR)/%.o: src/%.c | $(OBJDIR)
+ $(CC) -c $(CFLAGS) $< -o $@
+
+$(APP_NAME): $(OBJDIR)/$(APP_NAME).o
+ $(CC) $< -o $@
+
+### EOF \ No newline at end of file
diff --git a/util_ack/readme.md b/util_ack/readme.md
new file mode 100644
index 0000000..9de6a40
--- /dev/null
+++ b/util_ack/readme.md
@@ -0,0 +1,65 @@
+ / _____) _ | |
+ ( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+ (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Utility: packet acknowledger
+=============================
+
+1. Introduction
+----------------
+
+The packet acknowledger is a simple helper program listening on a single UDP
+port and responding to PUSH_DATA datagrams with PUSH_ACK, and to PULL_DATA
+datagrams with PULL_ACK.
+
+Informations about the datagrams received and the answers send are display on
+screen to help communication debugging.
+
+Packets not following the protocol detailed in the PROTOCOL.TXT document in the
+basic_pkt_fwt directory are ignored.
+
+2. Dependencies
+----------------
+
+This program follows the v1.1 version of the gateway-to-server protocol.
+
+3. Usage
+---------
+
+Start the program with the port number as first and only argument.
+
+To stop the application, press Ctrl+C.
+
+4. License
+-----------
+
+Copyright (C) 2013, SEMTECH S.A.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+* Neither the name of the Semtech corporation nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL SEMTECH S.A. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*EOF* \ No newline at end of file
diff --git a/util_ack/src/util_ack.c b/util_ack/src/util_ack.c
new file mode 100644
index 0000000..7acd32e
--- /dev/null
+++ b/util_ack/src/util_ack.c
@@ -0,0 +1,193 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ Network sink, receives UDP packets and sends an acknowledge
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+Maintainer: Sylvain Miermont
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+/* fix an issue between POSIX and C99 */
+#if __STDC_VERSION__ >= 199901L
+ #define _XOPEN_SOURCE 600
+#else
+ #define _XOPEN_SOURCE 500
+#endif
+
+#include <stdint.h> /* C99 types */
+#include <stdio.h> /* printf, fprintf, sprintf, fopen, fputs */
+#include <unistd.h> /* usleep */
+
+#include <string.h> /* memset */
+#include <time.h> /* time, clock_gettime, strftime, gmtime, clock_nanosleep*/
+#include <stdlib.h> /* atoi, exit */
+#include <errno.h> /* error messages */
+
+#include <sys/socket.h> /* socket specific definitions */
+#include <netinet/in.h> /* INET constants and stuff */
+#include <arpa/inet.h> /* IP address conversion stuff */
+#include <netdb.h> /* gai_strerror */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#define STRINGIFY(x) #x
+#define STR(x) STRINGIFY(x)
+#define MSG(args...) fprintf(stderr, args) /* message that is destined to the user */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define PROTOCOL_VERSION 2
+
+#define PKT_PUSH_DATA 0
+#define PKT_PUSH_ACK 1
+#define PKT_PULL_DATA 2
+#define PKT_PULL_RESP 3
+#define PKT_PULL_ACK 4
+
+/* -------------------------------------------------------------------------- */
+/* --- MAIN FUNCTION -------------------------------------------------------- */
+
+int main(int argc, char **argv)
+{
+ int i; /* loop variable and temporary variable for return value */
+
+ /* server socket creation */
+ int sock; /* socket file descriptor */
+ struct addrinfo hints;
+ struct addrinfo *result; /* store result of getaddrinfo */
+ struct addrinfo *q; /* pointer to move into *result data */
+ char host_name[64];
+ char port_name[64];
+
+ /* variables for receiving and sending packets */
+ struct sockaddr_storage dist_addr;
+ socklen_t addr_len = sizeof dist_addr;
+ uint8_t databuf[4096];
+ int byte_nb;
+
+ /* variables for protocol management */
+ uint32_t raw_mac_h; /* Most Significant Nibble, network order */
+ uint32_t raw_mac_l; /* Least Significant Nibble, network order */
+ uint64_t gw_mac; /* MAC address of the client (gateway) */
+ uint8_t ack_command;
+
+ /* check if port number was passed as parameter */
+ if (argc != 2) {
+ MSG("Usage: util_ack <port number>\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* prepare hints to open network sockets */
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC; /* should handle IP v4 or v6 automatically */
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_PASSIVE; /* will assign local IP automatically */
+
+ /* look for address */
+ i = getaddrinfo(NULL, argv[1], &hints, &result);
+ if (i != 0) {
+ MSG("ERROR: getaddrinfo returned %s\n", gai_strerror(i));
+ exit(EXIT_FAILURE);
+ }
+
+ /* try to open socket and bind it */
+ for (q=result; q!=NULL; q=q->ai_next) {
+ sock = socket(q->ai_family, q->ai_socktype,q->ai_protocol);
+ if (sock == -1) {
+ continue; /* socket failed, try next field */
+ } else {
+ i = bind(sock, q->ai_addr, q->ai_addrlen);
+ if (i == -1) {
+ shutdown(sock, SHUT_RDWR);
+ continue; /* bind failed, try next field */
+ } else {
+ break; /* success, get out of loop */
+ }
+ }
+ }
+ if (q == NULL) {
+ MSG("ERROR: failed to open socket or to bind to it\n");
+ i = 1;
+ for (q=result; q!=NULL; q=q->ai_next) {
+ getnameinfo(q->ai_addr, q->ai_addrlen, host_name, sizeof host_name, port_name, sizeof port_name, NI_NUMERICHOST);
+ MSG("INFO: result %i host:%s service:%s\n", i, host_name, port_name);
+ ++i;
+ }
+ exit(EXIT_FAILURE);
+ }
+ MSG("INFO: util_ack listening on port %s\n", argv[1]);
+ freeaddrinfo(result);
+
+ while (1) {
+ /* wait to receive a packet */
+ byte_nb = recvfrom(sock, databuf, sizeof databuf, 0, (struct sockaddr *)&dist_addr, &addr_len);
+ if (byte_nb == -1) {
+ MSG("ERROR: recvfrom returned %s \n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ /* display info about the sender */
+ i = getnameinfo((struct sockaddr *)&dist_addr, addr_len, host_name, sizeof host_name, port_name, sizeof port_name, NI_NUMERICHOST);
+ if (i == -1) {
+ MSG("ERROR: getnameinfo returned %s \n", gai_strerror(i));
+ exit(EXIT_FAILURE);
+ }
+ printf(" -> pkt in , host %s (port %s), %i bytes", host_name, port_name, byte_nb);
+
+ /* check and parse the payload */
+ if (byte_nb < 12) { /* not enough bytes for packet from gateway */
+ printf(" (too short for GW <-> MAC protocol)\n");
+ continue;
+ }
+ /* don't touch the token in position 1-2, it will be sent back "as is" for acknowledgement */
+ if (databuf[0] != PROTOCOL_VERSION) { /* check protocol version number */
+ printf(", invalid version %u\n", databuf[0]);
+ continue;
+ }
+ raw_mac_h = *((uint32_t *)(databuf+4));
+ raw_mac_l = *((uint32_t *)(databuf+8));
+ gw_mac = ((uint64_t)ntohl(raw_mac_h) << 32) + (uint64_t)ntohl(raw_mac_l);
+
+ /* interpret gateway command */
+ switch (databuf[3]) {
+ case PKT_PUSH_DATA:
+ printf(", PUSH_DATA from gateway 0x%08X%08X\n", (uint32_t)(gw_mac >> 32), (uint32_t)(gw_mac & 0xFFFFFFFF));
+ ack_command = PKT_PUSH_ACK;
+ printf("<- pkt out, PUSH_ACK for host %s (port %s)", host_name, port_name);
+ break;
+ case PKT_PULL_DATA:
+ printf(", PULL_DATA from gateway 0x%08X%08X\n", (uint32_t)(gw_mac >> 32), (uint32_t)(gw_mac & 0xFFFFFFFF));
+ ack_command = PKT_PULL_ACK;
+ printf("<- pkt out, PULL_ACK for host %s (port %s)", host_name, port_name);
+ break;
+ default:
+ printf(", unexpected command %u\n", databuf[3]);
+ continue;
+ }
+
+ /* add some artificial latency */
+ usleep(30000); /* 30 ms */
+
+ /* send acknowledge and check return value */
+ databuf[3] = ack_command;
+ byte_nb = sendto(sock, (void *)databuf, 4, 0, (struct sockaddr *)&dist_addr, addr_len);
+ if (byte_nb == -1) {
+ printf(", send error:%s\n", strerror(errno));
+ } else {
+ printf(", %i bytes sent\n", byte_nb);
+ }
+ }
+}