2 * Mausezahn - A fast versatile traffic generator
3 * Copyright (C) 2008-2010 Herbert Haas
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License version 2 as published by the
7 * Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
26 // Returns integer number for given tag string
27 // For example xml_tag2int("field") => xml_field == 1
29 // Returns -1 when tag not known
30 int xml_tag2int (char *t
)
32 if (!strncasecmp(t
, "protocol", XML_MAX_TAG_LEN
))
35 if (!strncasecmp(t
, "field", XML_MAX_TAG_LEN
))
38 if (!strncasecmp(t
, "name", XML_MAX_TAG_LEN
))
41 if (!strncasecmp(t
, "desc", XML_MAX_TAG_LEN
))
44 if (!strncasecmp(t
, "requires", XML_MAX_TAG_LEN
))
47 if (!strncasecmp(t
, "conflicts", XML_MAX_TAG_LEN
))
50 if (!strncasecmp(t
, "payloadtype", XML_MAX_TAG_LEN
))
51 return xml_payloadtype
;
53 if (!strncasecmp(t
, "payload", XML_MAX_TAG_LEN
))
56 if (!strncasecmp(t
, "payloadhex", XML_MAX_TAG_LEN
))
57 return xml_payloadhex
;
59 if (!strncasecmp(t
, "index", XML_MAX_TAG_LEN
))
62 if (!strncasecmp(t
, "longdesc", XML_MAX_TAG_LEN
))
65 if (!strncasecmp(t
, "type", XML_MAX_TAG_LEN
))
68 if (!strncasecmp(t
, "constant", XML_MAX_TAG_LEN
))
71 if (!strncasecmp(t
, "value", XML_MAX_TAG_LEN
))
74 if (!strncasecmp(t
, "valname", XML_MAX_TAG_LEN
))
77 if (!strncasecmp(t
, "min", XML_MAX_TAG_LEN
))
80 if (!strncasecmp(t
, "max", XML_MAX_TAG_LEN
))
83 if (!strncasecmp(t
, "tlvt", XML_MAX_TAG_LEN
))
86 if (!strncasecmp(t
, "tlvl", XML_MAX_TAG_LEN
))
89 if (!strncasecmp(t
, "lshift", XML_MAX_TAG_LEN
))
96 // For a given pair of tag t and parent p check
97 // if t is really an allowed child of p.
98 // RETURN VALUE: 0 if correct, -1 otherwise
100 int xml_check_parent(int t
, int p
)
102 // For given tag t specify allowed parent p
110 // has protocol as parent
114 case xml_payloadtype
:
117 if (p
==xml_protocol
) return 0;
120 // has field OR protocol as parent
123 if ((p
==xml_protocol
)||(p
==xml_field
)) return 0;
126 // has field as parent
138 if (p
==xml_field
) return 0;
145 // Parse a single protocol definition.
146 // The string 'p' must start with '<protocol>' and end with </protocol>
148 // RETURN VALUE: 0 upon success, >0 otherwise.
150 int parse_protocol (char *p
)
153 char p_clone
[AUTOMOPS_MAX_FILE_SIZE
+1];
154 struct automops
*new_amp
;
156 // Make a local copy of the protocol definition
157 strncpy(p_clone
, p
, AUTOMOPS_MAX_FILE_SIZE
);
158 p_clone
[AUTOMOPS_MAX_FILE_SIZE
]='\0';
160 // Check if XML form is correct.
161 // I thought that this check should be done separately (and not during
162 // the xml_readin() function) for safety reasons. If read-in plus
163 // validation would be combined, we would have more to clean-up at in
164 // case the XML data is corrupt.
165 i
= xml_canonic (p_clone
);
167 // If incorrect, tell where error is:
168 if ((!quiet
) && (i
)) {
170 fprintf(stderr
, "(EE) Mausezahn automops xml parse error:\n"
171 "========================================\n"
172 "%s <<ERROR>>\n", p_clone
);
173 fprintf(stderr
, "(EE) Error occured at character number %i\n", i
);
174 fprintf(stderr
," --- (printed all valid data until error position) ---\n");
178 fprintf(stderr
, "...XML verification finished.\n");
181 // XML is correct, now create automops entry
184 strncpy(p_clone
, p
, AUTOMOPS_MAX_FILE_SIZE
);
185 p_clone
[AUTOMOPS_MAX_FILE_SIZE
]='\0';
186 new_amp
= automops_alloc_protocol(amp_head
);
187 i
= xml_readin(new_amp
, p_clone
);
189 if ((!quiet
) && (i
)) {
192 fprintf(stderr
, "(EE) Invalid XML data at position %i: %s <<ERROR>>\n",
194 fprintf(stderr
," --- (printed all valid data until error position) ---\n");
196 automops_delete_protocol(new_amp
);
204 // Scans p until the next tag is found and stores
205 // tag name in t which must be a string of size
206 // XML_STRLEN (at least).
209 // >0 if opening tag is found
210 // 0 if no tag is found or other problem
211 // <0 if closing tag is found
213 // If any tag is found the absolut return value
214 // indicates the position AFTER the tag, e. g.
215 // ...<tag>... or ...</tag>...
218 // Upon problem, the errorness char number is
219 // stored as string within t along with the
220 // error reason as string.
222 int xml_getnext_tag (char *p
, char *t
)
228 // are there non-white characters left?
229 len
= strnlen(p
, AUTOMOPS_MAX_FILE_SIZE
);
230 for (i
=0; i
<len
; i
++) if (!isspace(p
[i
])) j
=1; // flag for first non-space character found
231 if (!j
) { // no more characters found
236 // basic length checks
238 if ((len
<3)||(len
==AUTOMOPS_MAX_FILE_SIZE
)) { // 3 is minimum tag length
239 snprintf(t
, XML_STRLEN
, "invalid length (%u)",len
);
244 // find first opening ('<') bracket
246 if (p
[i
]=='<') break;
250 // tag too close to end
252 snprintf(t
, XML_STRLEN
, "%4i - no end", i
);
253 return 0; // no tag found (smallest tag is '<x>')
265 // find closing bracket
274 snprintf(t
, XML_STRLEN
, "%4i - no end?", i
);
277 } while (i
<(j
+XML_MAX_TAG_LEN
+1));
279 // closing '>' really found?
281 sprintf(t
, "%4i - closing bracket missing", i
);
285 // now the tag name is from p[j]..p[k-1]
287 memcpy((void*) t
, (void*) &p
[j
], k
-j
);
294 // Copies data between opening and closing XML tags
295 // into 't' and returns the length of the data in bytes
296 // or zero if nothing found
297 // or -1 if protocol or data length is too long
298 // Note: Assumes that *p points to first byte after opening tag!
299 int xml_get_data (char *p
, char *t
)
303 // basic length checks
304 len
= strnlen(p
, AUTOMOPS_MAX_FILE_SIZE
);
305 if (len
==0) return 0;
307 if (len
>AUTOMOPS_MAX_FILE_SIZE
) {
308 snprintf(t
, XML_STRLEN
, "invalid length (%u)",len
);
313 // i. e. next opening ('<') bracket
315 if (p
[i
]=='<') break;
319 // Set limit on data length
320 if (i
>1500) return -1; // TODO: consider more reasonable limit
323 memcpy((void*) t
, (void*) &p
[0], i
);
330 // Make some simple checks whether XML data correct
331 // Currently only checks if
332 // - every opening tag has an ending tag (only via verbose now)
333 // - tags are properly nested (only 1st order tests now)
335 // RETURN VALUE: 0 upon success
336 // or position of mistake
338 int xml_canonic (char *p
)
340 int i
=0, l
, dlen
=0, plen
, xntag
=-1;
344 struct xnstack stack
, *s
;
350 fprintf(stderr
, "Parsing {%s}\n\n", p
);
353 plen
= strnlen(p
, AUTOMOPS_MAX_FILE_SIZE
);
356 l
= xml_getnext_tag (p
, t
); // Now t contains next tag name and l tells whether open or closing
358 if (t
[0]==0x00) // no more tag found
360 else { // general failure
361 fprintf(stderr
, "%s\n", t
);
368 fprintf(stderr
, "%4i %4i stack=%i %s%s>\n",i
,l
,xnstack_size(s
),
369 (l
>0) ? "<" : "</", t
);
371 if (i
>=plen
) { // break condition (regular, not an error!)
374 p
+=abs(l
); // now p points to first byte after tag
376 if (xml_tag2int(t
)<0) {
377 fprintf(stderr
, "mz/xml_canonic: UNKNOWN TAG at position %i\n", i
);
381 // Closing tag found: does it match last opening tag?
383 if (xml_tag2int(t
)!=xnstack_pop(s
)) {
385 fprintf(stderr
, "mz/xml_canonic: Incoherent nesting at position %i\n", i
);
391 // Opening tag found: store it in last_tag!
393 xntag
=xml_tag2int(t
);
394 // Check if this tag has proper parent
395 if (xml_check_parent(xntag
, xnstack_get_top(s
))) {
396 fprintf(stderr
, "mz/xml_canonic: Wrong parent tag\n");
399 if (xnstack_push(s
, xntag
)==-1) {
401 fprintf(stderr
, "mz/xml_canonic: max nesting depth exceeded\n");
406 dlen
= xml_get_data (p
, d
);
409 fprintf(stderr
, "mz/xml_canonic: %s\n", d
);
413 if ((dlen
>0) && (verbose
==2)) {
414 fprintf(stderr
, " %s\n", d
); // the data
419 if (i
==plen
-1) return 0;
422 if (xnstack_size(s
)!=0) {
423 fprintf(stderr
,"mz/xml_canonic: number of opening and closing tags does not match!\n");
432 // Copy data elements of *p into struct *amp
433 // =============================================================
434 // NOTE: THE XML STRUCTURE MUST BE CORRECT !!!
435 // NO XML CHECKS ARE DONE TO KEEP THIS FUNCTION SMALL !!!
436 // THEREFORE ALWAYS RUN xml_canonic() FIRST !!!
437 // =============================================================
439 // However, this function checks if the *data* is valid.
441 // RETURN VALUE: 0 upon success,
442 // otherwise character position of wrong data
444 int xml_readin (struct automops
*amp
, char *p
)
446 int i
=0, l
, dlen
=0, plen
, xntag
=-1, parent
=-1, err
=0;
448 char d
[1500], errmsg
[64];
450 struct xnstack stack
, *s
;
451 struct fields
*f
=NULL
;
456 plen
= strnlen(p
, AUTOMOPS_MAX_FILE_SIZE
);
459 l
= xml_getnext_tag (p
, t
); // Now t contains next tag name and l tells whether open or closing
461 if (t
[0]==0x00) return 0;
466 if (i
>=plen
) { // break condition (regular, not an error!)
469 p
+=abs(l
); // now p points to first byte after tag
472 // Closing tag found: does it match last opening tag?
473 if (l
<0) xnstack_pop(s
);
475 // Opening tag found: store it in last_tag!
477 xntag
=xml_tag2int(t
);
478 parent
=xnstack_get_top(s
); // get parent tag;
479 xnstack_push(s
, xntag
);
480 dlen
= xml_get_data (p
, d
);
482 if (xntag
==xml_field
) { // Create new field
483 f
=automops_add_field(amp
);
485 // Now copy the data 'd' into (the header & fields of) 'amp'
487 if (parent
==xml_protocol
) {
488 err
= amp_add_pentry(amp
, xntag
, d
);
490 if (parent
==xml_field
) {
491 err
= amp_add_fentry(amp
, f
, xntag
, d
);
495 amperr2str(err
, errmsg
);
496 fprintf(stderr
, "WARNING: Automops found '%s' at XML position %i\n", errmsg
, i
);
502 if (i
==(plen
-1)) return 0;
523 ///////////////////////////////////////////////////////////////////////////////
525 ////////////// ONLY XML NESTING STACK FUNCTIONS BELOW THIS LINE ///////////////
529 void xnstack_init(struct xnstack
*s
)
534 // Returns top data element or -1 if stack empty
535 // Does NOT remove data elements!
536 int xnstack_get_top(struct xnstack
*s
)
538 if (s
->cursize
==0) return -1;
539 return s
->data
[s
->cursize
-1];
542 // Push data onto stack
543 // Returns -1 if max stack depth exceeded
544 int xnstack_push(struct xnstack
*s
, int d
)
546 if (s
->cursize
<XN_MAX_STACK
)
547 s
->data
[s
->cursize
++]=d
;
554 // Returns top data element and ALSO REMOVES it from stack
555 // Returns -1 if stack is empty
556 int xnstack_pop(struct xnstack
*s
)
559 d
=xnstack_get_top(s
);
560 if (d
>=0) s
->cursize
--;
564 int xnstack_size(struct xnstack
*s
)