1+ /**
2+ * \file src/plugins/intermediate/asn/asn.c
3+ * \author Adam Zvara <[email protected] > 4+ * \brief Configuration parser of ASN plugin (source file)
5+ * \date 2023
6+ */
7+
8+ /* Copyright (C) 2018 CESNET, z.s.p.o.
9+ *
10+ * Redistribution and use in source and binary forms, with or without
11+ * modification, are permitted provided that the following conditions
12+ * are met:
13+ * 1. Redistributions of source code must retain the above copyright
14+ * notice, this list of conditions and the following disclaimer.
15+ * 2. Redistributions in binary form must reproduce the above copyright
16+ * notice, this list of conditions and the following disclaimer in
17+ * the documentation and/or other materials provided with the
18+ * distribution.
19+ * 3. Neither the name of the Company nor the names of its contributors
20+ * may be used to endorse or promote products derived from this
21+ * software without specific prior written permission.
22+ *
23+ * ALTERNATIVELY, provided that this notice is retained in full, this
24+ * product may be distributed under the terms of the GNU General Public
25+ * License (GPL) version 2 or later, in which case the provisions
26+ * of the GPL apply INSTEAD OF those given above.
27+ *
28+ * This software is provided ``as is'', and any express or implied
29+ * warranties, including, but not limited to, the implied warranties of
30+ * merchantability and fitness for a particular purpose are disclaimed.
31+ * In no event shall the company or contributors be liable for any
32+ * direct, indirect, incidental, special, exemplary, or consequential
33+ * damages (including, but not limited to, procurement of substitute
34+ * goods or services; loss of use, data, or profits; or business
35+ * interruption) however caused and on any theory of liability, whether
36+ * in contract, strict liability, or tort (including negligence or
37+ * otherwise) arising in any way out of the use of this software, even
38+ * if advised of the possibility of such damage.
39+ *
40+ */
41+
42+ #include <stdlib.h>
43+ #include <unistd.h> // access()
44+ #include <errno.h>
45+ #include "config.h"
46+
47+ /*
48+ * <params>
49+ * <field>
50+ <pen>0</pen>
51+ <id>1234</id>
52+ <type>string</type>
53+ <value>"ABCD"</value>
54+ <times>1</times>
55+ </field>
56+ * </params>
57+ */
58+
59+ // Strings used for parsing out type from XML file
60+ #define STRING_TYPE "string"
61+ #define INT_TYPE "integer"
62+ #define DOUBLE_TYPE "double"
63+
64+ /** XML nodes */
65+ enum params_xml_nodes {
66+ FIELD ,
67+ PEN ,
68+ ID ,
69+ TYPE ,
70+ VALUE ,
71+ TIMES
72+ };
73+
74+ // New fields
75+ static const struct fds_xml_args fields_schema [] = {
76+ FDS_OPTS_ELEM (PEN , "pen" , FDS_OPTS_T_UINT , 0 ),
77+ FDS_OPTS_ELEM (ID , "id" , FDS_OPTS_T_UINT , 0 ),
78+ FDS_OPTS_ELEM (TYPE , "type" , FDS_OPTS_T_STRING , 0 ),
79+ FDS_OPTS_ELEM (VALUE , "value" , FDS_OPTS_T_STRING , 0 ),
80+ FDS_OPTS_ELEM (TIMES , "times" , FDS_OPTS_T_UINT , FDS_OPTS_P_OPT ),
81+ FDS_OPTS_END
82+ };
83+
84+
85+ /** Definition of the \<params\> node */
86+ static const struct fds_xml_args args_params [] = {
87+ FDS_OPTS_ROOT ("params" ),
88+ FDS_OPTS_NESTED (FIELD , "field" , fields_schema , FDS_OPTS_P_OPT | FDS_OPTS_P_MULTI ),
89+ FDS_OPTS_END
90+ };
91+
92+ static int
93+ config_parser_fields (ipx_ctx_t * ctx , fds_xml_ctx_t * fields_ctx , struct dummy_config * cfg )
94+ {
95+ const struct fds_xml_cont * fields ;
96+ static size_t field_idx = 0 ;
97+ cfg -> fields [field_idx ].times = 1 ;
98+
99+ while (fds_xml_next (fields_ctx , & fields ) != FDS_EOC ) {
100+ switch (fields -> id ) {
101+ case PEN :
102+ cfg -> fields [field_idx ].pen = fields -> val_uint ;
103+ break ;
104+
105+ case ID :
106+ cfg -> fields [field_idx ].id = fields -> val_uint ;
107+ break ;
108+
109+ case TYPE :
110+ if (strcmp (fields -> ptr_string , INT_TYPE ) == 0 ) {
111+ cfg -> fields [field_idx ].type = DUMMY_FIELD_INT ;
112+ } else if (strcmp (fields -> ptr_string , STRING_TYPE ) == 0 ) {
113+ cfg -> fields [field_idx ].type = DUMMY_FIELD_STRING ;
114+ } else if (strcmp (fields -> ptr_string , DOUBLE_TYPE ) == 0 ) {
115+ cfg -> fields [field_idx ].type = DUMMY_FIELD_DOUBLE ;
116+ } else {
117+ IPX_CTX_ERROR (ctx , "Unknown type of field \"type\"" );
118+ return IPX_ERR_FORMAT ;
119+ }
120+ break ;
121+
122+ case VALUE :
123+ if (cfg -> fields [field_idx ].type == DUMMY_FIELD_INT ) {
124+ int int_value = strtol (fields -> ptr_string , NULL , 10 );
125+ cfg -> fields [field_idx ].value .integer = int_value ;
126+ } else if (cfg -> fields [field_idx ].type == DUMMY_FIELD_STRING ) {
127+ cfg -> fields [field_idx ].value .string = strdup (fields -> ptr_string );
128+ if (cfg -> fields [field_idx ].value .string == NULL ) {
129+ IPX_CTX_ERROR (ctx , "Memory allocation failed (%s:%d)" , __FILE__ , __LINE__ );
130+ return IPX_ERR_NOMEM ;
131+ }
132+ } else if (cfg -> fields [field_idx ].type == DUMMY_FIELD_DOUBLE ) {
133+ int double_value = strtod (fields -> ptr_string , NULL );
134+ int64_t tmp_num = htobe64 (le64toh (* (int64_t * )& double_value ));
135+ double dst_num = * (double * )& tmp_num ;
136+ cfg -> fields [field_idx ].value .decimal = dst_num ;
137+ }
138+ break ;
139+
140+ case TIMES :
141+ cfg -> fields [field_idx ].times = fields -> val_uint ;
142+ break ;
143+
144+ default :
145+ IPX_CTX_ERROR (ctx , "Unknown field in configuration (ID %d)" , fields -> id );
146+ return IPX_ERR_FORMAT ;
147+ }
148+
149+ }
150+
151+ field_idx ++ ;
152+ return IPX_OK ;
153+ }
154+
155+ /**
156+ * \brief Process \<params\> node
157+ * \param[in] ctx Plugin context
158+ * \param[in] root XML context to process
159+ * \param[in] cfg Parsed configuration
160+ * \return #IPX_OK on success
161+ * \return #IPX_ERR_FORMAT in case of failure
162+ */
163+ static int
164+ config_parser_root (ipx_ctx_t * ctx , fds_xml_ctx_t * root , struct dummy_config * cfg )
165+ {
166+ (void ) ctx ;
167+ const struct fds_xml_cont * content ;
168+
169+ // First, get number of new fields and allocate memory in config structure
170+ while (fds_xml_next (root , & content ) != FDS_EOC ) {
171+ if (content -> id != FIELD ) {
172+ // Non-field definition
173+ assert (false);
174+ continue ;
175+ }
176+ cfg -> fields_count ++ ;
177+ }
178+
179+ cfg -> fields = calloc (cfg -> fields_count , sizeof (* cfg -> fields ));
180+ if (!cfg -> fields ) {
181+ IPX_CTX_ERROR (ctx , "Memory allocation error (%s:%d)" , __FILE__ , __LINE__ );
182+ return IPX_ERR_FORMAT ;
183+ }
184+
185+ // Rewind pointer and start parsing
186+ fds_xml_rewind (root );
187+ while (fds_xml_next (root , & content ) != FDS_EOC ) {
188+ if (content -> id != FIELD ) {
189+ return IPX_ERR_FORMAT ;
190+ }
191+
192+ assert (content -> type == FDS_OPTS_T_CONTEXT );
193+ if (config_parser_fields (ctx , content -> ptr_ctx , cfg ) != IPX_OK ) {
194+ return IPX_ERR_FORMAT ;
195+ }
196+ }
197+
198+ return IPX_OK ;
199+ }
200+
201+ struct dummy_config *
202+ config_parse (ipx_ctx_t * ctx , const char * params )
203+ {
204+ struct dummy_config * cfg = calloc (1 , sizeof (* cfg ));
205+ if (!cfg ) {
206+ IPX_CTX_ERROR (ctx , "Memory allocation error (%s:%d)" , __FILE__ , __LINE__ );
207+ return NULL ;
208+ }
209+
210+ // Create an XML parser
211+ fds_xml_t * parser = fds_xml_create ();
212+ if (!parser ) {
213+ IPX_CTX_ERROR (ctx , "Memory allocation error (%s:%d)" , __FILE__ , __LINE__ );
214+ free (cfg );
215+ return NULL ;
216+ }
217+ if (fds_xml_set_args (parser , args_params ) != IPX_OK ) {
218+ IPX_CTX_ERROR (ctx , "Failed to parse the description of an XML document!" , '\0' );
219+ fds_xml_destroy (parser );
220+ free (cfg );
221+ return NULL ;
222+ }
223+
224+ fds_xml_ctx_t * params_ctx = fds_xml_parse_mem (parser , params , true);
225+ if (params_ctx == NULL ) {
226+ IPX_CTX_ERROR (ctx , "Failed to parse the configuration: %s" , fds_xml_last_err (parser ));
227+ fds_xml_destroy (parser );
228+ free (cfg );
229+ return NULL ;
230+ }
231+
232+ // Parse parameters
233+ int rc = config_parser_root (ctx , params_ctx , cfg );
234+ fds_xml_destroy (parser );
235+ if (rc != IPX_OK ) {
236+ free (cfg );
237+ return NULL ;
238+ }
239+
240+ return cfg ;
241+ }
242+
243+ void
244+ config_destroy (struct dummy_config * cfg )
245+ {
246+ for (uint32_t i = 0 ; i < cfg -> fields_count ; ++ i ) {
247+ if (cfg -> fields [i ].type == DUMMY_FIELD_STRING ) {
248+ free (cfg -> fields [i ].value .string );
249+ }
250+ }
251+ free (cfg -> fields );
252+ free (cfg );
253+ }
0 commit comments