mrpd: add parse module
authorAndrew Elder <aelder@audioscience.com>
Thu, 27 Sep 2012 00:09:09 +0000 (20:09 -0400)
committerAndrew Elder <aelder@audioscience.com>
Fri, 5 Oct 2012 10:48:13 +0000 (06:48 -0400)
daemons/common/parse.c [new file with mode: 0644]
daemons/common/parse.h [new file with mode: 0644]
daemons/mrpd/Makefile
daemons/mrpd/msrp.c

diff --git a/daemons/common/parse.c b/daemons/common/parse.c
new file mode 100644 (file)
index 0000000..b001157
--- /dev/null
@@ -0,0 +1,131 @@
+/****************************************************************************
+  Copyright (c) 2012, AudioScience, Inc
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+   2. 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.
+
+   3. Neither the name of the Intel 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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
+
+******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#include "parse.h"
+
+int parse(const char *s, struct parse_param *specs, int *err_index)
+{
+       int err = 0;
+       char *param;
+       char *data;
+       char *delimiter;
+       char *guard;
+       int v_int;
+       unsigned int v_uint;
+       uint64_t v_uint64;
+       int result;
+       int count = 0;
+
+       guard = s + strlen(s);
+
+       while (specs->name && !err) {
+               param = strstr(s, specs->name);
+               data = param + strlen(specs->name);
+
+               /* temporarily terminate string at next delimiter */
+               delimiter = data;
+               while ((*delimiter != PARSE_DELIMITER) && (delimiter < guard))
+                       *delimiter++;
+               if (delimiter < guard)
+                       *delimiter = 0;
+
+               switch (specs->type) {
+               case parse_null:
+                       break;
+               case parse_u8:
+                       result = sscanf(data, "%d", &v_uint);
+                       if (result == 1)
+                               *(uint8_t *) specs->v = (uint8_t) v_uint;
+                       break;
+               case parse_u16:
+                       result = sscanf(data, "%d", &v_uint);
+                       if (result == 1)
+                               *(uint16_t *) specs->v = (uint16_t) v_uint;
+                       break;
+               case parse_u32:
+                       result = sscanf(data, "%d", &v_uint);
+                       if (result == 1)
+                               *(uint32_t *) specs->v = v_uint;
+                       break;
+               case parse_u64:
+                       result = sscanf(data, "%" SCNu64, &v_uint64);
+                       if (result == 1)
+                               *(uint64_t *) specs->v = v_uint64;
+                       break;
+               case parse_h64:
+                       result = sscanf(data, "%" SCNx64, &v_uint64);
+                       if (result == 1)
+                               *(uint64_t *) specs->v = v_uint64;
+                       break;
+               case parse_c64:
+                       /* read as uint64_t, then unpack to array */
+                       result = sscanf(data, "%" SCNx64, &v_uint64);
+                       if (result == 1) {
+                               int i;
+                               uint8_t *p = (uint8_t *) specs->v;
+                               for (i = 0; i < 8; i++) {
+                                       int shift = (7 - i) * 8;
+                                       p[i] = (uint8_t) (v_uint64 >> shift);
+                               }
+                       }
+                       break;
+               case parse_mac:
+                       /* read as uint64_t, then unpack to array */
+                       result = sscanf(data, "%" SCNx64, &v_uint64);
+                       if (result == 1) {
+                               int i;
+                               uint8_t *p = (uint8_t *) specs->v;
+                               for (i = 0; i < 6; i++) {
+                                       int shift = (5 - i) * 8;
+                                       p[i] = (uint8_t) (v_uint64 >> shift);
+                               }
+                       }
+                       break;
+               }
+               if (result != 1) {
+                       *err_index = count + 1;
+                       return -1;
+               }
+
+               if (delimiter < guard)
+                       s = delimiter + 1;
+               specs++;
+               count++;
+       }
+       *err_index = 0;
+       return 0;
+}
diff --git a/daemons/common/parse.h b/daemons/common/parse.h
new file mode 100644 (file)
index 0000000..740c45d
--- /dev/null
@@ -0,0 +1,58 @@
+/****************************************************************************
+  Copyright (c) 2012, AudioScience, Inc
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+   2. 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.
+
+   3. Neither the name of the Intel 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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
+
+******************************************************************************/
+
+#ifndef PARSE_H_
+#define PARSE_H_
+
+enum parse_types {
+       parse_null,
+       parse_u8,       /* uint8_t v */
+       parse_u16,      /* uint16_t v */
+       parse_u32,      /* uint32_t v */
+       parse_u64,      /* uint64_t v */
+       parse_h64,      /* uint64_t v */
+       parse_c64,      /* uint8_t a[8] */
+       parse_mac       /* uint8_t m[6] */
+};
+
+#define PARSE_DELIMITER ':'
+#define PARSE_ASSIGN ":"
+
+struct parse_param {
+       char *name;
+       enum parse_types type;
+       void *v;
+};
+
+int parse(const char *s, struct parse_param *specs, int *err_index);
+
+#endif                         /* PARSE_H_ */
index 3a6f0ff..c2ed77e 100644 (file)
@@ -3,13 +3,15 @@ OPT=-O2
 CFLAGS=$(OPT) -Wall -W -Wno-parentheses -ggdb -D_GNU_SOURCE
 
 CC=gcc
-#INCFLAGS=-I../lib
+INCFLAGS=-I../common
 #LDLIBS=-ligb -lpci
 #LDFLAGS=-L../lib
 
 all: mrpd mrpctl
 
-mrpd: mrpd.o mvrp.o msrp.o mmrp.o mrp.o
+VPATH = ../common
+
+mrpd: mrpd.o mvrp.o msrp.o mmrp.o mrp.o parse.o
 
 mrpctl: mrpctl.o
 
index 6ce9cb5..bdd923c 100644 (file)
@@ -38,6 +38,7 @@
 #include <stddef.h>
 #include <string.h>
 
+#include "parse.h"
 #include "mrpd.h"
 #include "mrp.h"
 #include "msrp.h"
@@ -2355,19 +2356,284 @@ int msrp_dumptable(struct sockaddr_in *client)
 
 }
 
+
+int msrp_test_cmd_parse_join_or_new_stream(
+               char *buf, int buflen,
+               struct msrpdu_talker_fail *talker_ad
+)
+{
+       int err, err_index;
+
+       struct parse_param specs[] = {
+               {"S" PARSE_ASSIGN, parse_c64, talker_ad->StreamID},
+               {"A" PARSE_ASSIGN, parse_mac, talker_ad->DataFrameParameters.Dest_Addr},
+               {"V" PARSE_ASSIGN, parse_u16, &talker_ad->DataFrameParameters.Vlan_ID},
+               {"Z" PARSE_ASSIGN, parse_u16, &talker_ad->TSpec.MaxFrameSize},
+               {"I" PARSE_ASSIGN, parse_u16, &talker_ad->TSpec.MaxIntervalFrames},
+               {"P" PARSE_ASSIGN, parse_u8, &talker_ad->PriorityAndRank},
+               {"L" PARSE_ASSIGN, parse_u32, &talker_ad->AccumulatedLatency},
+               {0, parse_null, 0}
+       };
+       memset(talker_ad, 0, sizeof(*talker_ad));
+       return parse(buf, specs, &err_index);
+}
+
+/* S+? - (re)JOIN a stream */
+/* S++ - NEW a stream      */
+
+int msrp_cmd_parse_join_or_new_stream(
+               char *buf, int buflen,
+               struct msrpdu_talker_fail *talker_ad
+)
+{
+       char *stream_str = NULL;
+       char *daddr_str = NULL;
+       char *vlan_str = NULL;
+       char *size_str = NULL;
+       char *interval_str = NULL;
+       char *prio_str = NULL;
+       char *latency_str = NULL;
+       uint8_t streamid_firstval[8];
+       uint8_t macvec_firstval[6];
+       uint8_t macvec_parsestr[64];
+       unsigned vlan, size, interval, prio, latency;
+       int i, rc;
+
+       memset(talker_ad, 0, sizeof(*talker_ad));
+               /*
+                * create or join a stream
+                * interesting to note the spec doesn't talk about
+                * what happens if two talkers attempt to define the identical
+                * stream twice  - does the bridge report STREAM_CHANGE error?
+                */
+
+               if (buflen < 22) {
+                       return -1;
+               }
+               /*
+                  buf[] should look similar to "S:%02x%02x%02x%02x%02x%02x%02x%02x"
+                  ":A:%02x%02x%02x%02x%02x%02x"
+                  ":V:%04x" \
+                  ":Z:%d" \
+                  ":I:%d" \
+                  ":P:%d" \
+                  ":L:%d" \
+                */
+
+               i = 0;
+
+               while (i < buflen) {
+                       if (buf[i] == ':') {
+                               stream_str = &(buf[i + 1]);
+                               i++;
+                               break;
+                       }
+                       i++;
+               }
+
+               if (i >= buflen) {
+                       return -1;
+               }
+
+               while (i < (buflen - 3)) {
+                       if ((buf[i] == ':') && (buf[i + 1] == 'A')
+                           && (buf[i + 2] == ':')) {
+                               buf[i] = '\0';
+                               daddr_str = &(buf[i + 3]);
+                               i += 4;
+                               break;
+                       }
+                       i++;
+               }
+
+               if (i >= (buflen - 3)) {
+                       return -1;
+               }
+
+               while (i < (buflen - 3)) {
+                       if ((buf[i] == ':') && (buf[i + 1] == 'V')
+                           && (buf[i + 2] == ':')) {
+                               buf[i] = '\0';
+                               vlan_str = &(buf[i + 3]);
+                               i += 4;
+                               break;
+                       }
+                       i++;
+               }
+
+               if (i >= (buflen - 3)) {
+                       return -1;
+               }
+
+               while (i < (buflen - 3)) {
+                       if ((buf[i] == ':') && (buf[i + 1] == 'Z')
+                           && (buf[i + 2] == ':')) {
+                               buf[i] = '\0';
+                               size_str = &(buf[i + 3]);
+                               i += 4;
+                               break;
+                       }
+                       i++;
+               }
+
+               if (i >= (buflen - 3)) {
+                       return -1;
+               }
+
+               while (i < (buflen - 3)) {
+                       if ((buf[i] == ':') && (buf[i + 1] == 'I')
+                           && (buf[i + 2] == ':')) {
+                               buf[i] = '\0';
+                               interval_str = &(buf[i + 3]);
+                               i += 4;
+                               break;
+                       }
+                       i++;
+               }
+
+               if (i >= (buflen - 3)) {
+                       return -1;
+               }
+
+               while (i < (buflen - 3)) {
+                       if ((buf[i] == ':') && (buf[i + 1] == 'P')
+                           && (buf[i + 2] == ':')) {
+                               buf[i] = '\0';
+                               prio_str = &(buf[i + 3]);
+                               i += 4;
+                               break;
+                       }
+                       i++;
+               }
+
+               if (i >= (buflen - 3)) {
+                       return -1;
+               }
+
+               while (i < (buflen - 3)) {
+                       if ((buf[i] == ':') && (buf[i + 1] == 'L')
+                           && (buf[i + 2] == ':')) {
+                               buf[i] = '\0';
+                               latency_str = &(buf[i + 3]);
+                               i += 4;
+                               break;
+                       }
+                       i++;
+               }
+
+               if (i >= (buflen - 3)) {
+                       return -1;
+               }
+
+               memset(macvec_parsestr, 0, sizeof(macvec_parsestr));
+
+               for (i = 0; i < 8; i++) {
+                       macvec_parsestr[0] = stream_str[i * 2];
+                       macvec_parsestr[1] = stream_str[i * 2 + 1];
+
+                       rc = sscanf((char *)macvec_parsestr, "%hhx",
+                                   &streamid_firstval[i]);
+                       if (0 == rc) {
+                               return -1;
+                       }
+               }
+
+               memset(macvec_parsestr, 0, sizeof(macvec_parsestr));
+               for (i = 0; i < 6; i++) {
+                       macvec_parsestr[0] = daddr_str[i * 2];
+                       macvec_parsestr[1] = daddr_str[i * 2 + 1];
+
+                       rc = sscanf((char *)macvec_parsestr, "%hhx",
+                                   &macvec_firstval[i]);
+                       if (0 == rc) {
+                               return -1;
+                       }
+               }
+
+               rc = sscanf((char *)vlan_str, "%x", &vlan);
+               if (0 == rc) {
+                       return -1;
+               }
+
+               rc = sscanf((char *)size_str, "%d", &size);
+               if (0 == rc) {
+                       return -1;
+               }
+
+               rc = sscanf((char *)interval_str, "%d", &interval);
+               if (0 == rc) {
+                       return -1;
+               }
+
+               rc = sscanf((char *)prio_str, "%d", &prio);
+               if (0 == rc) {
+                       return -1;
+               }
+
+               rc = sscanf((char *)latency_str, "%d", &latency);
+               if (0 == rc) {
+                       return -1;
+               }
+
+               memcpy(talker_ad->StreamID,
+                      streamid_firstval, 8);
+               memcpy(talker_ad->DataFrameParameters.Dest_Addr, macvec_firstval,
+                      6);
+               talker_ad->DataFrameParameters.Vlan_ID = vlan;
+               talker_ad->TSpec.MaxFrameSize = size;
+               talker_ad->TSpec.MaxIntervalFrames = interval;
+               talker_ad->PriorityAndRank = prio;
+               talker_ad->AccumulatedLatency = latency;
+
+
+       return 0;
+}
+
+/*
+ * Required fields are:
+ * talker_ad->StreamID
+ * talker_ad->DataFrameParameters.Dest_Addr
+ * talker_ad->DataFrameParameters.Vlan_ID
+ * talker_ad->TSpec.MaxFrameSize
+ * talker_ad->TSpec.MaxIntervalFrames
+ * talker_ad->PriorityAndRank
+ * talker_ad->AccumulatedLatency
+ *
+ */
+
+int msrp_cmd_join_or_new_stream(
+               int join,
+               struct msrpdu_talker_fail *talker_ad
+)
+{
+       struct msrp_attribute *attrib;
+
+       attrib = msrp_alloc();
+       if (NULL == attrib) {
+               return -1;
+       }
+       attrib->type = MSRP_TALKER_ADV_TYPE;
+       attrib->attribute.talk_listen = *talker_ad;
+       memset(attrib->registrar.macaddr, 0, 6);
+
+       if (join)
+               msrp_event(MRP_EVENT_JOIN, attrib);
+       else
+               msrp_event(MRP_EVENT_NEW, attrib);
+
+       return 0;
+}
+
 /*
 Future
 
-int msrp_cmd_parse_join_stream();
-int msrp_cmd_parse_new_stream();
+
 int msrp_cmd_parse_leave_stream();
 int msrp_cmd_parse_report_listener_status();
 int msrp_cmd_parse_withdraw_listener_status();
 int msrp_cmd_parse_report_domain_status();
 int msrp_cmd_parse_withdraw_domain_status();
 
-int msrp_cmd_join_stream();
-int msrp_cmd_new_stream();
 int msrp_cmd_leave_stream();
 int msrp_cmd_report_listener_status();
 int msrp_cmd_withdraw_listener_status();
@@ -2393,6 +2659,7 @@ int msrp_recv_cmd(char *buf, int buflen, struct sockaddr_in *client)
        uint8_t macvec_parsestr[64];
        unsigned vlan, size, interval, prio, latency;
        int i;
+       //struct msrpdu_talker_fail t0,t1;
 
        if (NULL == MSRP_db) {
                snprintf(respbuf, sizeof(respbuf) - 1, "ERC %s", buf);
@@ -2477,8 +2744,7 @@ int msrp_recv_cmd(char *buf, int buflen, struct sockaddr_in *client)
                        if (buflen < 18) {
                                snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s",
                                         buf);
-                               mrpd_send_ctl_msg(client, respbuf,
-                                                 sizeof(respbuf));
+                               mrpd_send_ctl_msg(client, respbuf, sizeof(respbuf));
                                goto out;
                        }
                        /* buf[] should look similar to 'S-D:C:%d:P:%d:V:%04x" */
@@ -3025,6 +3291,16 @@ int msrp_recv_cmd(char *buf, int buflen, struct sockaddr_in *client)
                        attrib->attribute.talk_listen.AccumulatedLatency =
                            latency;
 
+                       /*
+                       msrp_cmd_parse_join_or_new_stream(buf, buflen, &t0);
+                       msrp_test_cmd_parse_join_or_new_stream(buf+3, buflen, &t1);
+
+                       if(memcmp(&t0, &t1, sizeof(t0))==0)
+                               printf("parse match\n");
+                       if(memcmp(&t0,&attrib->attribute.talk_listen,sizeof(t0)))
+                               printf("old and new parse match\n");
+                       */
+
                        if (join)
                                msrp_event(MRP_EVENT_JOIN, attrib);
                        else